Skip to content

Commit eb583ab

Browse files
MariefayTrigger.dev RepoOps
authored andcommitted
feat(webapp): turn on progressive trace loading and trace API paging for everyone
The run page now loads large traces progressively and updates live runs incrementally, and the run trace API can page large traces with `page[size]` and `page[after]`. Mono-RevId: 928f7102a88b948176d94a9da1f0420866aa5193
1 parent fc33769 commit eb583ab

5 files changed

Lines changed: 19 additions & 49 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: improvement
4+
---
5+
6+
The run page now loads large traces progressively and updates live runs incrementally, so big traces open faster and open run pages no longer reload the whole trace while a run is executing. The run trace API can also page large traces.

‎apps/webapp/app/presenters/v3/RunPresenter.server.ts‎

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import type { SpanSummary } from "~/v3/eventRepository/eventRepository.types";
66
import { getTaskEventStoreTableForRun } from "~/v3/taskEventStore.server";
77
import { isFinalRunStatus } from "~/v3/taskStatus";
88
import { env } from "~/env.server";
9-
import { FEATURE_FLAG } from "~/v3/featureFlags";
10-
import { makeFlag } from "~/v3/featureFlags.server";
119
import { getEventRepositoryForStore } from "~/v3/eventRepository/index.server";
1210
import { canLiveTail } from "./liveTailGate";
1311
import { assembleFirstTraceChunk, type TraceReadScope } from "./traceFirstChunk.server";
@@ -131,7 +129,7 @@ export class RunPresenter {
131129
slug: projectSlug,
132130
organization: { members: { some: { userId } } },
133131
},
134-
select: { id: true, organization: { select: { featureFlags: true } } },
132+
select: { id: true },
135133
});
136134

137135
if (!authorizedProject) {
@@ -209,31 +207,20 @@ export class RunPresenter {
209207
? millisecondsToNanoseconds(run.startedAt.getTime() - triggeredAt.getTime())
210208
: undefined;
211209

212-
const orgFeatureFlags =
213-
(authorizedProject.organization?.featureFlags as Record<string, unknown>) ?? {};
214-
215210
// Read before the first chunk so the first tail covers the background load.
216211
const firstChunkReadAt = Date.now();
217212

218-
const progressivePromise = makeFlag(this.#prismaClient)({
219-
key: FEATURE_FLAG.progressiveTraceLoadingEnabled,
220-
defaultValue: false,
221-
overrides: orgFeatureFlags,
222-
});
223-
224-
const firstChunkPromise = progressivePromise.then((progressiveEnabled) =>
225-
progressiveEnabled && canLiveTail(run.taskEventStore, env.TRACE_VIEW_EMERGENCY_SPAN_CAP)
226-
? repository.getTraceChunk(
227-
getTaskEventStoreTableForRun(run),
228-
environment.id,
229-
run.traceId,
230-
traceTimeBounds.startCreatedAt,
231-
traceTimeBounds.endCreatedAt,
232-
undefined,
233-
{ includeDebugLogs: showDebug }
234-
)
235-
: undefined
236-
);
213+
const firstChunkPromise = canLiveTail(run.taskEventStore, env.TRACE_VIEW_EMERGENCY_SPAN_CAP)
214+
? repository.getTraceChunk(
215+
getTaskEventStoreTableForRun(run),
216+
environment.id,
217+
run.traceId,
218+
traceTimeBounds.startCreatedAt,
219+
traceTimeBounds.endCreatedAt,
220+
undefined,
221+
{ includeDebugLogs: showDebug }
222+
)
223+
: Promise.resolve(undefined);
237224

238225
const [user, firstChunk] = await Promise.all([
239226
this.#prismaClient.user.findFirst({

‎apps/webapp/app/routes/api.v1.runs.$runId.trace.ts‎

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import {
1313
getTraceStartTimeEnd,
1414
} from "~/v3/eventRepository/traceInsertedAtBound";
1515
import { getRunTracePage } from "~/v3/eventRepository/runTracePage.server";
16-
import { FEATURE_FLAG } from "~/v3/featureFlags";
17-
import { makeFlag } from "~/v3/featureFlags.server";
1816
import { toPageSpan } from "~/v3/eventRepository/tracePage";
1917
import {
2018
DEFAULT_TRACE_PAGE_SIZE,
@@ -97,10 +95,7 @@ export const loader = createLoaderApiRoute(
9795
async ({ resource: resolved, authentication, request }) => {
9896
const searchParams = new URL(request.url).searchParams;
9997

100-
if (
101-
hasPageParams(searchParams) &&
102-
(await isTracePagingEnabled(authentication.environment.organization.featureFlags))
103-
) {
98+
if (hasPageParams(searchParams)) {
10499
const pageRequest = parseTracePageRequest(searchParams, DEFAULT_TRACE_PAGE_SIZE);
105100
if (pageRequest.isErr()) {
106101
return json({ error: PAGE_REQUEST_ERRORS[pageRequest.error] }, { status: 400 });
@@ -157,15 +152,6 @@ function hasPageParams(searchParams: URLSearchParams): boolean {
157152
return searchParams.has("page[size]") || searchParams.has("page[after]");
158153
}
159154

160-
// Off: page parameters are ignored and the request gets today's tree response.
161-
function isTracePagingEnabled(orgFeatureFlags: unknown): Promise<boolean> {
162-
return makeFlag()({
163-
key: FEATURE_FLAG.publicTracePagingEnabled,
164-
defaultValue: false,
165-
overrides: (orgFeatureFlags as Record<string, unknown>) ?? {},
166-
});
167-
}
168-
169155
const PAGE_REQUEST_ERRORS = {
170156
invalid_page_size: "page[size] must be a positive integer",
171157
invalid_cursor: "page[after] is not a valid cursor; pass back pagination.next unchanged",

‎apps/webapp/app/v3/featureFlags.ts‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ export const FEATURE_FLAG = {
5959
apiRateLimitMetricsEnabled: "apiRateLimitMetricsEnabled",
6060
queueArchivingEnabled: "queueArchivingEnabled",
6161
supportAccessSettingsEnabled: "supportAccessSettingsEnabled",
62-
progressiveTraceLoadingEnabled: "progressiveTraceLoadingEnabled",
63-
publicTracePagingEnabled: "publicTracePagingEnabled",
6462
runTokenInjection: "runTokenInjection",
6563
} as const;
6664

@@ -235,9 +233,6 @@ export const FeatureFlagCatalog = {
235233
// Shows the org Support Access settings page. Off until every webapp enforces the setting;
236234
// the org override wins over the global value.
237235
[FEATURE_FLAG.supportAccessSettingsEnabled]: z.boolean(),
238-
[FEATURE_FLAG.progressiveTraceLoadingEnabled]: z.boolean(),
239-
// Page parameters on the public trace API. Off: they're ignored and the tree is returned.
240-
[FEATURE_FLAG.publicTracePagingEnabled]: z.boolean(),
241236
// Injects a signed per-attempt TRIGGER_RUN_TOKEN into deployed runs. Org override wins over
242237
// the global value. Requires RUN_TOKEN_ISSUER_URL and an active internal run signing key.
243238
[FEATURE_FLAG.runTokenInjection]: z.boolean(),

‎docs/management/runs/retrieve-trace.mdx‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ title: "Retrieve run trace"
33
openapi: "v3-openapi GET /api/v1/runs/{runId}/trace"
44
---
55

6-
import { RollingOut } from "/snippets/feature-status.jsx";
7-
86
Returns the OpenTelemetry trace subtree for the run you request. The response `trace.rootSpan` is that run's span — not necessarily the trace-wide root — with its descendant spans nested under `children`.
97

108
For a child or nested run inside a large trace, this endpoint scopes the tree to that run so you still get a useful subtree even when the full trace has more spans than the platform can return in one response.
@@ -13,8 +11,6 @@ For a finished run, spans that finish more than 7 days after the run are returne
1311

1412
## Page large traces
1513

16-
<RollingOut flag="publicTracePagingEnabled" />
17-
1814
The tree response stops at a size limit. To get every span of a large trace, page it: send `page[size]` (1,000–10,000) on the first request, then pass each response's `pagination.next` back as `page[after]` until it's absent.
1915

2016
```ts Your backend code

0 commit comments

Comments
 (0)