Skip to content

Commit 26c82c5

Browse files
authored
Merge branch 'main' into limits-page-2
2 parents b691aa7 + a5339a1 commit 26c82c5

File tree

11 files changed

+63
-159
lines changed

11 files changed

+63
-159
lines changed

apps/webapp/app/components/primitives/TreeView/TreeView.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ export function useTree<TData, TFilterValue>({
527527
/** An actual tree structure with custom data */
528528
export type Tree<TData> = {
529529
id: string;
530+
runId?: string;
530531
children?: Tree<TData>[];
531532
data: TData;
532533
};
@@ -535,6 +536,7 @@ export type Tree<TData> = {
535536
export type FlatTreeItem<TData> = {
536537
id: string;
537538
parentId?: string | undefined;
539+
runId?: string;
538540
children: string[];
539541
hasChildren: boolean;
540542
/** The indentation level, the root is 0 */
@@ -552,6 +554,7 @@ export function flattenTree<TData>(tree: Tree<TData>): FlatTree<TData> {
552554
flatTree.push({
553555
id: node.id,
554556
parentId,
557+
runId: node.runId,
555558
children,
556559
hasChildren: children.length > 0,
557560
level,
@@ -571,6 +574,7 @@ export function flattenTree<TData>(tree: Tree<TData>): FlatTree<TData> {
571574
type FlatTreeWithoutChildren<TData> = {
572575
id: string;
573576
parentId: string | undefined;
577+
runId?: string;
574578
data: TData;
575579
};
576580

@@ -580,7 +584,7 @@ export function createTreeFromFlatItems<TData>(
580584
): Tree<TData> | undefined {
581585
// Index items by id
582586
const indexedItems: { [id: string]: Tree<TData> } = withoutChildren.reduce((acc, item) => {
583-
acc[item.id] = { id: item.id, data: item.data, children: [] };
587+
acc[item.id] = { id: item.id, runId: item.runId, data: item.data, children: [] };
584588
return acc;
585589
}, {} as { [id: string]: Tree<TData> });
586590

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ export class RunPresenter {
209209
//we need the start offset for each item, and the total duration of the entire tree
210210
const treeRootStartTimeMs = tree ? tree?.data.startTime.getTime() : 0;
211211
let totalDuration = tree?.data.duration ?? 0;
212+
213+
// Build the linkedRunIdBySpanId map during the same walk
214+
const linkedRunIdBySpanId: Record<string, string> = {};
215+
212216
const events = tree
213217
? flattenTree(tree).map((n) => {
214218
const offset = millisecondsToNanoseconds(
@@ -218,6 +222,12 @@ export class RunPresenter {
218222
if (!n.data.isDebug) {
219223
totalDuration = Math.max(totalDuration, offset + n.data.duration);
220224
}
225+
226+
// For cached spans, store the mapping from spanId to the linked run's ID
227+
if (n.data.style?.icon === "task-cached" && n.runId) {
228+
linkedRunIdBySpanId[n.id] = n.runId;
229+
}
230+
221231
return {
222232
...n,
223233
data: {
@@ -260,6 +270,7 @@ export class RunPresenter {
260270
? millisecondsToNanoseconds(run.startedAt.getTime() - run.createdAt.getTime())
261271
: undefined,
262272
overridesBySpanId: traceSummary.overridesBySpanId,
273+
linkedRunIdBySpanId,
263274
},
264275
maximumLiveReloadingSetting: eventRepository.maximumLiveReloadingSetting,
265276
};

apps/webapp/app/presenters/v3/SpanPresenter.server.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ export class SpanPresenter extends BasePresenter {
3535
projectSlug,
3636
spanId,
3737
runFriendlyId,
38+
linkedRunId,
3839
}: {
3940
userId: string;
4041
projectSlug: string;
4142
spanId: string;
4243
runFriendlyId: string;
44+
linkedRunId?: string;
4345
}) {
4446
const project = await this._replica.project.findFirst({
4547
where: {
@@ -88,6 +90,7 @@ export class SpanPresenter extends BasePresenter {
8890
traceId,
8991
eventRepository,
9092
spanId,
93+
linkedRunId,
9194
createdAt: parentRun.createdAt,
9295
completedAt: parentRun.completedAt,
9396
environmentId: parentRun.runtimeEnvironmentId,
@@ -126,6 +129,7 @@ export class SpanPresenter extends BasePresenter {
126129
traceId,
127130
eventRepository,
128131
spanId,
132+
linkedRunId,
129133
createdAt,
130134
completedAt,
131135
}: {
@@ -134,19 +138,12 @@ export class SpanPresenter extends BasePresenter {
134138
traceId: string;
135139
eventRepository: IEventRepository;
136140
spanId: string;
141+
linkedRunId?: string;
137142
createdAt: Date;
138143
completedAt: Date | null;
139144
}) {
140-
const originalRunId = await eventRepository.getSpanOriginalRunId(
141-
eventStore,
142-
environmentId,
143-
spanId,
144-
traceId,
145-
createdAt,
146-
completedAt ?? undefined
147-
);
148-
149-
const run = await this.findRun({ originalRunId, spanId, environmentId });
145+
// Use linkedRunId if provided (for cached spans), otherwise look up by spanId
146+
const run = await this.findRun({ originalRunId: linkedRunId, spanId, environmentId });
150147

151148
if (!run) {
152149
return;
@@ -272,7 +269,7 @@ export class SpanPresenter extends BasePresenter {
272269
workerQueue: run.workerQueue,
273270
traceId: run.traceId,
274271
spanId: run.spanId,
275-
isCached: !!originalRunId,
272+
isCached: !!linkedRunId,
276273
machinePreset: machine?.name,
277274
taskEventStore: run.taskEventStore,
278275
externalTraceId,

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,12 @@ function TraceView({
476476

477477
const spanOverrides = selectedSpanId ? overridesBySpanId?.[selectedSpanId] : undefined;
478478

479+
// Get the linked run ID for cached spans (map built during RunPresenter walk)
480+
const { linkedRunIdBySpanId } = trace;
481+
const selectedSpanLinkedRunId = selectedSpanId
482+
? linkedRunIdBySpanId?.[selectedSpanId]
483+
: undefined;
484+
479485
return (
480486
<div className={cn("grid h-full max-h-full grid-cols-1 overflow-hidden")}>
481487
<ResizablePanelGroup
@@ -526,6 +532,7 @@ function TraceView({
526532
spanId={selectedSpanId}
527533
spanOverrides={spanOverrides as SpanOverride | undefined}
528534
closePanel={() => replaceSearchParam("span")}
535+
linkedRunId={selectedSpanLinkedRunId}
529536
/>
530537
</ResizablePanel>
531538
)}

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
9393
const { projectParam, organizationSlug, envParam, runParam, spanParam } =
9494
v3SpanParamsSchema.parse(params);
9595

96+
const url = new URL(request.url);
97+
const linkedRunId = url.searchParams.get("linkedRunId") ?? undefined;
98+
9699
const presenter = new SpanPresenter();
97100

98101
try {
@@ -101,6 +104,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
101104
spanId: spanParam,
102105
runFriendlyId: runParam,
103106
userId,
107+
linkedRunId,
104108
});
105109

106110
return typedjson(result);
@@ -130,11 +134,13 @@ export function SpanView({
130134
spanId,
131135
spanOverrides,
132136
closePanel,
137+
linkedRunId,
133138
}: {
134139
runParam: string;
135140
spanId: string | undefined;
136141
spanOverrides?: SpanOverride;
137142
closePanel?: () => void;
143+
linkedRunId?: string;
138144
}) {
139145
const organization = useOrganization();
140146
const project = useProject();
@@ -143,10 +149,11 @@ export function SpanView({
143149

144150
useEffect(() => {
145151
if (spanId === undefined) return;
146-
fetcher.load(
147-
`/resources/orgs/${organization.slug}/projects/${project.slug}/env/${environment.slug}/runs/${runParam}/spans/${spanId}`
148-
);
149-
}, [organization.slug, project.slug, environment.slug, runParam, spanId]);
152+
const url = `/resources/orgs/${organization.slug}/projects/${project.slug}/env/${
153+
environment.slug
154+
}/runs/${runParam}/spans/${spanId}${linkedRunId ? `?linkedRunId=${linkedRunId}` : ""}`;
155+
fetcher.load(url);
156+
}, [organization.slug, project.slug, environment.slug, runParam, spanId, linkedRunId]);
150157

151158
if (spanId === undefined) {
152159
return null;
@@ -305,7 +312,12 @@ function RunBody({
305312
useEffect(() => {
306313
if (resetFetcher.data && resetFetcher.state === "idle") {
307314
// Check if the response indicates success
308-
if (resetFetcher.data && typeof resetFetcher.data === "object" && "success" in resetFetcher.data && resetFetcher.data.success === true) {
315+
if (
316+
resetFetcher.data &&
317+
typeof resetFetcher.data === "object" &&
318+
"success" in resetFetcher.data &&
319+
resetFetcher.data.success === true
320+
) {
309321
toast.custom(
310322
(t) => (
311323
<ToastUI
@@ -574,7 +586,11 @@ function RunBody({
574586
<div className="flex items-start justify-between gap-2">
575587
<div className="flex-1">
576588
{run.idempotencyKey ? (
577-
<CopyableText value={run.idempotencyKey} copyValue={run.idempotencyKey} asChild />
589+
<CopyableText
590+
value={run.idempotencyKey}
591+
copyValue={run.idempotencyKey}
592+
asChild
593+
/>
578594
) : (
579595
<div className="break-all"></div>
580596
)}
@@ -951,7 +967,9 @@ function RunBody({
951967
{run.logsDeletedAt === null ? (
952968
<>
953969
<LinkButton
954-
to={`${v3LogsPath(organization, project, environment)}?runId=${runParam}&from=${new Date(run.createdAt).getTime() - 60000}`}
970+
to={`${v3LogsPath(organization, project, environment)}?runId=${runParam}&from=${
971+
new Date(run.createdAt).getTime() - 60000
972+
}`}
955973
variant="secondary/medium"
956974
>
957975
View logs
@@ -968,8 +986,6 @@ function RunBody({
968986
</LinkButton>
969987
</>
970988
) : null}
971-
972-
973989
</div>
974990
</div>
975991
</div>

apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ import type {
5959
TraceEventOptions,
6060
TraceSummary,
6161
} from "./eventRepository.types";
62-
import { originalRunIdCache } from "./originalRunIdCache.server";
6362

6463
export type ClickhouseEventRepositoryConfig = {
6564
clickhouse: ClickHouse;
@@ -705,13 +704,6 @@ export class ClickhouseEventRepository implements IEventRepository {
705704
expires_at: convertDateToClickhouseDateTime(new Date(Date.now() + 365 * 24 * 60 * 60 * 1000)),
706705
};
707706

708-
const originalRunId =
709-
options.attributes.properties?.[SemanticInternalAttributes.ORIGINAL_RUN_ID];
710-
711-
if (typeof originalRunId === "string") {
712-
await originalRunIdCache.set(traceId, spanId, originalRunId);
713-
}
714-
715707
const events = [event];
716708

717709
if (failedWithError) {
@@ -1197,17 +1189,6 @@ export class ClickhouseEventRepository implements IEventRepository {
11971189
return span;
11981190
}
11991191

1200-
async getSpanOriginalRunId(
1201-
storeTable: TaskEventStoreTable,
1202-
environmentId: string,
1203-
spanId: string,
1204-
traceId: string,
1205-
startCreatedAt: Date,
1206-
endCreatedAt?: Date
1207-
): Promise<string | undefined> {
1208-
return await originalRunIdCache.lookup(traceId, spanId);
1209-
}
1210-
12111192
#mergeRecordsIntoSpanDetail(
12121193
spanId: string,
12131194
records: TaskEventDetailsV1Result[],

apps/webapp/app/v3/eventRepository/eventRepository.server.ts

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ import type {
6464
TraceEventOptions,
6565
TraceSummary,
6666
} from "./eventRepository.types";
67-
import { originalRunIdCache } from "./originalRunIdCache.server";
6867

6968
const MAX_FLUSH_DEPTH = 5;
7069

@@ -817,40 +816,6 @@ export class EventRepository implements IEventRepository {
817816
});
818817
}
819818

820-
async getSpanOriginalRunId(
821-
storeTable: TaskEventStoreTable,
822-
environmentId: string,
823-
spanId: string,
824-
traceId: string,
825-
startCreatedAt: Date,
826-
endCreatedAt?: Date
827-
): Promise<string | undefined> {
828-
return await startActiveSpan("getSpanOriginalRunId", async (s) => {
829-
return await originalRunIdCache.swr(traceId, spanId, async () => {
830-
const spanEvent = await this.#getSpanEvent({
831-
storeTable,
832-
spanId,
833-
environmentId,
834-
startCreatedAt,
835-
endCreatedAt,
836-
options: { includeDebugLogs: false },
837-
});
838-
839-
if (!spanEvent) {
840-
return;
841-
}
842-
// This is used when the span is a cached run (because of idempotency key)
843-
// so this span isn't the actual run span, but points to the original run
844-
const originalRun = rehydrateAttribute<string>(
845-
spanEvent.properties,
846-
SemanticInternalAttributes.ORIGINAL_RUN_ID
847-
);
848-
849-
return originalRun;
850-
});
851-
});
852-
}
853-
854819
async #createSpanFromEvent(
855820
storeTable: TaskEventStoreTable,
856821
event: PreparedEvent,

apps/webapp/app/v3/eventRepository/eventRepository.types.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -393,15 +393,6 @@ export interface IEventRepository {
393393
options?: { includeDebugLogs?: boolean }
394394
): Promise<SpanDetail | undefined>;
395395

396-
getSpanOriginalRunId(
397-
storeTable: TaskEventStoreTable,
398-
environmentId: string,
399-
spanId: string,
400-
traceId: string,
401-
startCreatedAt: Date,
402-
endCreatedAt?: Date
403-
): Promise<string | undefined>;
404-
405396
// Event recording methods
406397
recordEvent(
407398
message: string,

0 commit comments

Comments
 (0)