Skip to content

Commit 3b755d9

Browse files
committed
Improve attempt metrics when in a warm start, and pass the STYLE_VARIANT for a warm or cold start on attempt spans
1 parent b2cf5fe commit 3b755d9

File tree

13 files changed

+505
-223
lines changed

13 files changed

+505
-223
lines changed

apps/webapp/app/components/run/RunTimeline.tsx

+1-193
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { DateTime, DateTimeAccurate } from "../primitives/DateTime";
1111
import { LiveTimer } from "../runs/v3/LiveTimer";
1212
import tileBgPath from "~/assets/images/[email protected]";
1313
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../primitives/Tooltip";
14+
import { getHelpTextForEvent, TimelineSpanEvent } from "~/utils/timelineSpanEvents";
1415

1516
// Types for the RunTimeline component
1617
export type TimelineEventState = "complete" | "error" | "inprogress" | "delayed";
@@ -674,196 +675,3 @@ export function SpanTimeline({
674675
</>
675676
);
676677
}
677-
678-
export type TimelineSpanEvent = {
679-
name: string;
680-
offset: number;
681-
timestamp: Date;
682-
duration?: number;
683-
helpText?: string;
684-
markerVariant: TimelineEventVariant;
685-
lineVariant: TimelineLineVariant;
686-
};
687-
688-
export function createTimelineSpanEventsFromSpanEvents(
689-
spanEvents: SpanEvent[],
690-
isAdmin: boolean,
691-
relativeStartTime?: number
692-
): Array<TimelineSpanEvent> {
693-
// Rest of function remains the same
694-
if (!spanEvents) {
695-
return [];
696-
}
697-
698-
const matchingSpanEvents = spanEvents.filter((spanEvent) =>
699-
spanEvent.name.startsWith("trigger.dev/")
700-
);
701-
702-
if (matchingSpanEvents.length === 0) {
703-
return [];
704-
}
705-
706-
const sortedSpanEvents = [...matchingSpanEvents].sort((a, b) => {
707-
if (a.time === b.time) {
708-
return a.name.localeCompare(b.name);
709-
}
710-
711-
const aTime = typeof a.time === "string" ? new Date(a.time) : a.time;
712-
const bTime = typeof b.time === "string" ? new Date(b.time) : b.time;
713-
714-
return aTime.getTime() - bTime.getTime();
715-
});
716-
717-
const visibleSpanEvents = sortedSpanEvents.filter(
718-
(spanEvent) =>
719-
isAdmin ||
720-
!getAdminOnlyForEvent(
721-
"event" in spanEvent.properties && typeof spanEvent.properties.event === "string"
722-
? spanEvent.properties.event
723-
: spanEvent.name
724-
)
725-
);
726-
727-
if (visibleSpanEvents.length === 0) {
728-
return [];
729-
}
730-
731-
const firstEventTime =
732-
typeof visibleSpanEvents[0].time === "string"
733-
? new Date(visibleSpanEvents[0].time)
734-
: visibleSpanEvents[0].time;
735-
736-
const $relativeStartTime = relativeStartTime ?? firstEventTime.getTime();
737-
738-
const events = visibleSpanEvents.map((spanEvent, index) => {
739-
const timestamp =
740-
typeof spanEvent.time === "string" ? new Date(spanEvent.time) : spanEvent.time;
741-
742-
const offset = millisecondsToNanoseconds(timestamp.getTime() - $relativeStartTime);
743-
744-
const duration =
745-
"duration" in spanEvent.properties && typeof spanEvent.properties.duration === "number"
746-
? spanEvent.properties.duration
747-
: undefined;
748-
749-
const name =
750-
"event" in spanEvent.properties && typeof spanEvent.properties.event === "string"
751-
? spanEvent.properties.event
752-
: spanEvent.name;
753-
754-
let markerVariant: TimelineEventVariant = "dot-hollow";
755-
756-
if (index === 0) {
757-
markerVariant = "start-cap";
758-
}
759-
760-
return {
761-
name: getFriendlyNameForEvent(name),
762-
offset,
763-
timestamp,
764-
duration,
765-
properties: spanEvent.properties,
766-
helpText: getHelpTextForEvent(name),
767-
markerVariant,
768-
lineVariant: "light" as const,
769-
};
770-
});
771-
772-
// Now sort by offset, ascending
773-
events.sort((a, b) => a.offset - b.offset);
774-
775-
return events;
776-
}
777-
778-
function getFriendlyNameForEvent(event: string): string {
779-
switch (event) {
780-
case "dequeue": {
781-
return "Dequeued";
782-
}
783-
case "fork": {
784-
return "Launched";
785-
}
786-
case "create_attempt": {
787-
return "Attempt created";
788-
}
789-
case "import": {
790-
return "Imported task file";
791-
}
792-
case "lazy_payload": {
793-
return "Lazy attempt initialized";
794-
}
795-
case "pod_scheduled": {
796-
return "Pod scheduled";
797-
}
798-
default: {
799-
return event;
800-
}
801-
}
802-
}
803-
804-
function getAdminOnlyForEvent(event: string): boolean {
805-
switch (event) {
806-
case "dequeue": {
807-
return false;
808-
}
809-
case "fork": {
810-
return false;
811-
}
812-
case "create_attempt": {
813-
return true;
814-
}
815-
case "import": {
816-
return true;
817-
}
818-
case "lazy_payload": {
819-
return true;
820-
}
821-
case "pod_scheduled": {
822-
return true;
823-
}
824-
default: {
825-
return true;
826-
}
827-
}
828-
}
829-
830-
function getHelpTextForEvent(event: string): string | undefined {
831-
switch (event) {
832-
case "dequeue": {
833-
return "The run was dequeued from the queue";
834-
}
835-
case "fork": {
836-
return "The process was created to run the task";
837-
}
838-
case "create_attempt": {
839-
return "An attempt was created for the run";
840-
}
841-
case "import": {
842-
return "A task file was imported";
843-
}
844-
case "lazy_payload": {
845-
return "The payload was initialized lazily";
846-
}
847-
case "pod_scheduled": {
848-
return "The Kubernetes pod was scheduled to run";
849-
}
850-
case "Triggered": {
851-
return "The run was triggered";
852-
}
853-
case "Dequeued": {
854-
return "The run was dequeued from the queue";
855-
}
856-
case "Started": {
857-
return "The run began executing";
858-
}
859-
case "Finished": {
860-
return "The run completed execution";
861-
}
862-
case "Expired": {
863-
return "The run expired before it could be started";
864-
}
865-
default: {
866-
return undefined;
867-
}
868-
}
869-
}

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { millisecondsToNanoseconds } from "@trigger.dev/core/v3";
22
import { createTreeFromFlatItems, flattenTree } from "~/components/primitives/TreeView/TreeView";
3-
import { createTimelineSpanEventsFromSpanEvents } from "~/components/run/RunTimeline";
43
import { prisma, PrismaClient } from "~/db.server";
5-
import { redirectWithErrorMessage } from "~/models/message.server";
4+
import { createTimelineSpanEventsFromSpanEvents } from "~/utils/timelineSpanEvents";
65
import { getUsername } from "~/utils/username";
76
import { eventRepository } from "~/v3/eventRepository.server";
87
import { getTaskEventStoreTableForRun } from "~/v3/taskEventStore.server";

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

+2-6
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,7 @@ import {
3636
import { TabButton, TabContainer } from "~/components/primitives/Tabs";
3737
import { TextLink } from "~/components/primitives/TextLink";
3838
import { InfoIconTooltip, SimpleTooltip } from "~/components/primitives/Tooltip";
39-
import {
40-
createTimelineSpanEventsFromSpanEvents,
41-
RunTimeline,
42-
RunTimelineEvent,
43-
SpanTimeline,
44-
} from "~/components/run/RunTimeline";
39+
import { RunTimeline, RunTimelineEvent, SpanTimeline } from "~/components/run/RunTimeline";
4540
import { RunIcon } from "~/components/runs/v3/RunIcon";
4641
import { RunTag } from "~/components/runs/v3/RunTag";
4742
import { SpanEvents } from "~/components/runs/v3/SpanEvents";
@@ -76,6 +71,7 @@ import { useEnvironment } from "~/hooks/useEnvironment";
7671
import { WaitpointStatusCombo } from "~/components/runs/v3/WaitpointStatus";
7772
import { PacketDisplay } from "~/components/runs/v3/PacketDisplay";
7873
import { WaitpointDetailTable } from "~/components/runs/v3/WaitpointDetails";
74+
import { createTimelineSpanEventsFromSpanEvents } from "~/utils/timelineSpanEvents";
7975

8076
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
8177
const { projectParam, organizationSlug, envParam, runParam, spanParam } =

0 commit comments

Comments
 (0)