From 30c625f81303010df6fc277594bc38714b6484f1 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Thu, 10 Apr 2025 14:04:26 +0100 Subject: [PATCH 1/7] WIP on hiding the queued time --- .../app/presenters/v3/RunPresenter.server.ts | 6 ++ .../route.tsx | 76 +++++++++++++++---- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/apps/webapp/app/presenters/v3/RunPresenter.server.ts b/apps/webapp/app/presenters/v3/RunPresenter.server.ts index f2a8dece51..b235dacded 100644 --- a/apps/webapp/app/presenters/v3/RunPresenter.server.ts +++ b/apps/webapp/app/presenters/v3/RunPresenter.server.ts @@ -50,6 +50,7 @@ export class RunPresenter { spanId: true, friendlyId: true, status: true, + startedAt: true, completedAt: true, logsDeletedAt: true, rootTaskRun: { @@ -104,6 +105,7 @@ export class RunPresenter { spanId: run.spanId, status: run.status, isFinished: isFinalRunStatus(run.status), + startedAt: run.startedAt, completedAt: run.completedAt, logsDeletedAt: showDeletedLogs ? null : run.logsDeletedAt, rootTaskRun: run.rootTaskRun, @@ -201,6 +203,10 @@ export class RunPresenter { tree?.id === traceSummary.rootSpan.id ? undefined : traceSummary.rootSpan.runId, duration: totalDuration, rootStartedAt: tree?.data.startTime, + startedAt: run.startedAt, + queuedDuration: run.startedAt + ? millisecondsToNanoseconds(run.startedAt.getTime() - run.createdAt.getTime()) + : undefined, }, }; } diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx index 24ee6e6123..4c314a66fc 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx @@ -295,7 +295,8 @@ function TraceView({ run, trace, maximumLiveReloadingSetting, resizable }: Loade return <>; } - const { events, parentRunFriendlyId, duration, rootSpanStatus, rootStartedAt } = trace; + const { events, parentRunFriendlyId, duration, rootSpanStatus, rootStartedAt, queuedDuration } = + trace; const shouldLiveReload = events.length <= maximumLiveReloadingSetting; const changeToSpan = useDebounce((selectedSpan: string) => { @@ -345,6 +346,7 @@ function TraceView({ run, trace, maximumLiveReloadingSetting, resizable }: Loade totalDuration={duration} rootSpanStatus={rootSpanStatus} rootStartedAt={rootStartedAt ? new Date(rootStartedAt) : undefined} + queuedDuration={queuedDuration} environmentType={run.environment.type} shouldLiveReload={shouldLiveReload} maximumLiveReloadingSetting={maximumLiveReloadingSetting} @@ -472,6 +474,7 @@ type TasksTreeViewProps = { totalDuration: number; rootSpanStatus: "executing" | "completed" | "failed"; rootStartedAt: Date | undefined; + queuedDuration: number | undefined; environmentType: RuntimeEnvironmentType; shouldLiveReload: boolean; maximumLiveReloadingSetting: number; @@ -491,6 +494,7 @@ function TasksTreeView({ totalDuration, rootSpanStatus, rootStartedAt, + queuedDuration, environmentType, shouldLiveReload, maximumLiveReloadingSetting, @@ -502,12 +506,14 @@ function TasksTreeView({ const [errorsOnly, setErrorsOnly] = useState(false); const [showDebug, setShowDebug] = useState(false); const [showDurations, setShowDurations] = useState(true); + const [showQueueTime, setShowQueueTime] = useState(false); const [scale, setScale] = useState(0); const parentRef = useRef(null); const treeScrollRef = useRef(null); const timelineScrollRef = useRef(null); const displayEvents = showDebug ? events : events.filter((event) => !event.data.isDebug); + const queuedTime = showQueueTime ? undefined : queuedDuration; const { nodes, @@ -556,6 +562,12 @@ function TasksTreeView({ onCheckedChange={(e) => setShowDebug(e.valueOf())} /> )} + setShowQueueTime(e.valueOf())} + /> & { scale: number; parentRef: React.RefObject; @@ -785,27 +798,32 @@ function TimelineView({ toggleNodeSelection, showDurations, treeScrollRef, + queuedDuration, }: TimelineViewProps) { - const isAdmin = useHasAdminAccess(); const timelineContainerRef = useRef(null); const initialTimelineDimensions = useInitialDimensions(timelineContainerRef); const minTimelineWidth = initialTimelineDimensions?.width ?? 300; const maxTimelineWidth = minTimelineWidth * 10; //we want to live-update the duration if the root span is still executing - const [duration, setDuration] = useState(totalDuration); + const [duration, setDuration] = useState(queueAdjustedNs(totalDuration, queuedDuration)); useEffect(() => { if (rootSpanStatus !== "executing" || !rootStartedAt) { - setDuration(totalDuration); + setDuration(queueAdjustedNs(totalDuration, queuedDuration)); return; } const interval = setInterval(() => { - setDuration(millisecondsToNanoseconds(Date.now() - rootStartedAt.getTime())); + setDuration( + queueAdjustedNs( + millisecondsToNanoseconds(Date.now() - rootStartedAt.getTime()), + queuedDuration + ) + ); }, 500); return () => clearInterval(interval); - }, [totalDuration, rootSpanStatus]); + }, [totalDuration, rootSpanStatus, queuedDuration, rootStartedAt]); return (
{/* Follows the cursor */} - + {/* The duration labels */} @@ -941,7 +963,9 @@ function TimelineView({ eventIndex === 0 ? ( {(ms) => ( {(ms) => ( @@ -975,7 +1001,9 @@ function TimelineView({ node.data.timelineEvents[0] && node.data.timelineEvents[0].offset < node.data.offset ? ( ) : ( - + {(ms) => ( @@ -1235,7 +1279,11 @@ function CurrentTimeIndicator({ offset = lerp(0.5, 1, (ratio - (1 - edgeBoundary)) / edgeBoundary); } - const currentTime = rootStartedAt ? new Date(rootStartedAt.getTime() + ms) : undefined; + const currentTime = rootStartedAt + ? new Date( + rootStartedAt.getTime() + ms + nanosecondsToMilliseconds(queuedDurationNs ?? 0) + ) + : undefined; const currentTimeComponent = currentTime ? : <>; return ( From 6e6eddbe8233e48aee77fbfce8c4904cf2ed4bea Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Thu, 10 Apr 2025 14:41:19 +0100 Subject: [PATCH 2/7] Fix for position/sizes of spans --- .../route.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx index 4c314a66fc..7a94b0dd98 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx @@ -1017,11 +1017,11 @@ function TimelineView({ Date: Thu, 10 Apr 2025 14:43:56 +0100 Subject: [PATCH 3/7] Fix for duration squashing --- .../route.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx index 7a94b0dd98..879c05440b 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx @@ -1239,19 +1239,22 @@ function SpanWithDuration({ style={{ backgroundImage: `url(${tileBgPath})`, backgroundSize: "8px 8px" }} /> )} -
-
+ {formatDurationMilliseconds(props.durationMs, { style: "short", maxDecimalPoints: props.durationMs < 1000 ? 0 : 1, })} -
-
+
+
); From 21ff0a21616900da80ea62d8313d4891b26d3b24 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Thu, 10 Apr 2025 15:18:19 +0100 Subject: [PATCH 4/7] Tweaked some styles on the timeline --- .../route.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx index 879c05440b..517b8a5a4d 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx @@ -942,6 +942,8 @@ function TimelineView({ getTreeProps={getTreeProps} parentClassName="h-full scrollbar-hide" renderNode={({ node, state, index, virtualizer, virtualItem }) => { + const isTopSpan = node.id === events[0]?.id; + return ( ( ) : ( @@ -1036,7 +1039,7 @@ function TimelineView({ {(ms) => ( {node.data.isPartial && ( From 1df05b0efad6d1eb318e852438ed1df5716fd2ed Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Thu, 10 Apr 2025 16:04:57 +0100 Subject: [PATCH 5/7] Fix for retry spans appearing in the wrong place --- apps/webapp/app/v3/runEngineHandlers.server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/v3/runEngineHandlers.server.ts b/apps/webapp/app/v3/runEngineHandlers.server.ts index 6f236cf3ed..1a71157289 100644 --- a/apps/webapp/app/v3/runEngineHandlers.server.ts +++ b/apps/webapp/app/v3/runEngineHandlers.server.ts @@ -333,6 +333,7 @@ export function registerRunEngineEventBusHandlers() { } await eventRepository.recordEvent(retryMessage, { + startTime: BigInt(time.getTime() * 1000000), taskSlug: run.taskIdentifier, environment, attributes: { @@ -347,7 +348,6 @@ export function registerRunEngineEventBusHandlers() { queueName: run.queue, }, context: run.traceContext as Record, - spanIdSeed: `retry-${run.attemptNumber + 1}`, endTime: retryAt, }); } catch (error) { From a47600d3665949e97975153d456d3a5a3a1362d0 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Thu, 10 Apr 2025 16:05:12 +0100 Subject: [PATCH 6/7] =?UTF-8?q?Added=20=E2=80=9CQ=E2=80=9D=20shortcut=20ke?= =?UTF-8?q?y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../route.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx index 517b8a5a4d..dcb1331b78 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx @@ -567,6 +567,7 @@ function TasksTreeView({ label="Queue time" checked={showQueueTime} onCheckedChange={(e) => setShowQueueTime(e.valueOf())} + shortcut={{ key: "Q" }} /> toggleExpandLevel(number)} /> + {}} /> ); } From f309c6f6fb76abac99783af4f06e4672a29b3555 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Thu, 10 Apr 2025 16:26:49 +0100 Subject: [PATCH 7/7] Fix for in progress span durations --- .../route.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx index dcb1331b78..84331e7ae7 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx @@ -1024,8 +1024,15 @@ function TimelineView({ )} durationMs={ node.data.duration - ? nanosecondsToMilliseconds(Math.min(node.data.duration, duration)) - : nanosecondsToMilliseconds(duration - node.data.offset) + ? //completed + nanosecondsToMilliseconds(Math.min(node.data.duration, duration)) + : //in progress + nanosecondsToMilliseconds( + Math.min( + duration + (queuedDuration ?? 0) - node.data.offset, + duration + ) + ) } node={node} fadeLeft={isTopSpan && queuedDuration !== undefined}