Skip to content

Commit ff69578

Browse files
committed
feat(webapp): record deployment outcome span at terminal status
1 parent 93bdf83 commit ff69578

6 files changed

Lines changed: 102 additions & 0 deletions

apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
} from "./createBackgroundWorker.server";
1616
import { findOrCreateBackgroundWorker } from "./createDeploymentBackgroundWorkerV4/findOrCreateBackgroundWorker.server";
1717
import { TimeoutDeploymentService } from "./timeoutDeployment.server";
18+
import { recordDeploymentOutcome } from "./recordDeploymentOutcome.server";
1819
import { env } from "~/env.server";
1920

2021
export class CreateDeploymentBackgroundWorkerServiceV4 extends BaseService {
@@ -297,6 +298,14 @@ export class CreateDeploymentBackgroundWorkerServiceV4 extends BaseService {
297298
// sibling attempt may have just enqueued it as part of a successful
298299
// BUILDING → DEPLOYING transition.
299300
await TimeoutDeploymentService.dequeue(deployment.id, this._prisma);
301+
302+
recordDeploymentOutcome({
303+
status: "FAILED",
304+
deploymentFriendlyId: deployment.friendlyId,
305+
projectId: deployment.projectId,
306+
environmentId: deployment.environmentId,
307+
reason: error.message,
308+
});
300309
}
301310

302311
throw error;

apps/webapp/app/v3/services/deploymentIndexFailed.server.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BaseService } from "./baseService.server";
33
import { logger } from "~/services/logger.server";
44
import { type WorkerDeploymentStatus } from "@trigger.dev/database";
55
import { DeploymentService } from "./deployment.server";
6+
import { recordDeploymentOutcome } from "./recordDeploymentOutcome.server";
67

78
const FINAL_DEPLOYMENT_STATUSES: WorkerDeploymentStatus[] = [
89
"CANCELED",
@@ -74,6 +75,16 @@ export class DeploymentIndexFailed extends BaseService {
7475
},
7576
});
7677

78+
recordDeploymentOutcome({
79+
status: "FAILED",
80+
deploymentFriendlyId: deployment.friendlyId,
81+
organizationId: deployment.environment.project.organizationId,
82+
projectId: deployment.environment.projectId,
83+
environmentId: deployment.environmentId,
84+
environmentType: deployment.environment.type,
85+
reason: error.message,
86+
});
87+
7788
const deploymentService = new DeploymentService();
7889
await deploymentService
7990
.appendToEventLog(deployment.environment.project, failedDeployment, [

apps/webapp/app/v3/services/failDeployment.server.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { type WorkerDeploymentStatus } from "@trigger.dev/database";
55
import { type FailDeploymentRequestBody } from "@trigger.dev/core/v3/schemas";
66
import { type AuthenticatedEnvironment } from "~/services/apiAuth.server";
77
import { DeploymentService } from "./deployment.server";
8+
import { recordDeploymentOutcome } from "./recordDeploymentOutcome.server";
89

910
export const FINAL_DEPLOYMENT_STATUSES: WorkerDeploymentStatus[] = [
1011
"CANCELED",
@@ -51,6 +52,16 @@ export class FailDeploymentService extends BaseService {
5152
},
5253
});
5354

55+
recordDeploymentOutcome({
56+
status: "FAILED",
57+
deploymentFriendlyId: friendlyId,
58+
organizationId: authenticatedEnv.organizationId,
59+
projectId: authenticatedEnv.projectId,
60+
environmentId: authenticatedEnv.id,
61+
environmentType: authenticatedEnv.type,
62+
reason: params.error.message,
63+
});
64+
5465
const deploymentService = new DeploymentService();
5566
await deploymentService
5667
.appendToEventLog(authenticatedEnv.project, failedDeployment, [

apps/webapp/app/v3/services/finalizeDeployment.server.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { projectPubSub } from "./projectPubSub.server";
1010
import { FailDeploymentService } from "./failDeployment.server";
1111
import { TimeoutDeploymentService } from "./timeoutDeployment.server";
1212
import { DeploymentService } from "./deployment.server";
13+
import { recordDeploymentOutcome } from "./recordDeploymentOutcome.server";
1314
import { engine } from "../runEngine.server";
1415
import { tryCatch } from "@trigger.dev/core";
1516

@@ -78,6 +79,15 @@ export class FinalizeDeploymentService extends BaseService {
7879
},
7980
});
8081

82+
recordDeploymentOutcome({
83+
status: "DEPLOYED",
84+
deploymentFriendlyId: deployment.friendlyId,
85+
organizationId: authenticatedEnv.organizationId,
86+
projectId: authenticatedEnv.projectId,
87+
environmentId: authenticatedEnv.id,
88+
environmentType: authenticatedEnv.type,
89+
});
90+
8191
const deploymentService = new DeploymentService();
8292
await deploymentService
8393
.appendToEventLog(authenticatedEnv.project, finalizedDeployment, [
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { SpanStatusCode } from "@opentelemetry/api";
2+
import { type WorkerDeploymentStatus } from "@trigger.dev/database";
3+
import { logger } from "~/services/logger.server";
4+
import { tracer } from "~/v3/tracer.server";
5+
6+
type TerminalDeploymentStatus = Extract<
7+
WorkerDeploymentStatus,
8+
"DEPLOYED" | "FAILED" | "TIMED_OUT" | "CANCELED"
9+
>;
10+
11+
/**
12+
* Records a deployment's terminal status as a `deployment.outcome` span so
13+
* deploy success/failure is queryable from traces (no DB read). Call after each
14+
* terminal-status write. Org/project/env are best-effort; never throws.
15+
*/
16+
export function recordDeploymentOutcome(params: {
17+
status: TerminalDeploymentStatus;
18+
deploymentFriendlyId: string;
19+
organizationId?: string;
20+
projectId?: string;
21+
environmentId?: string;
22+
environmentType?: string;
23+
reason?: string;
24+
}): void {
25+
try {
26+
const span = tracer.startSpan("deployment.outcome", {
27+
attributes: {
28+
"$trigger.org.id": params.organizationId,
29+
"$trigger.project.id": params.projectId,
30+
"$trigger.env.id": params.environmentId,
31+
"$trigger.env.type": params.environmentType,
32+
"deployment.outcome.status": params.status,
33+
"deployment.outcome.success": params.status === "DEPLOYED",
34+
"deployment.outcome.deployment_id": params.deploymentFriendlyId,
35+
"deployment.outcome.reason": params.reason,
36+
},
37+
});
38+
39+
if (params.status !== "DEPLOYED") {
40+
span.setStatus({ code: SpanStatusCode.ERROR, message: params.reason });
41+
}
42+
43+
span.end();
44+
} catch (error) {
45+
logger.debug("recordDeploymentOutcome failed", {
46+
deploymentFriendlyId: params.deploymentFriendlyId,
47+
error: error instanceof Error ? error.message : String(error),
48+
});
49+
}
50+
}

apps/webapp/app/v3/services/timeoutDeployment.server.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { PerformDeploymentAlertsService } from "./alerts/performDeploymentAlerts
55
import { type PrismaClientOrTransaction } from "~/db.server";
66
import { workerQueue } from "~/services/worker.server";
77
import { DeploymentService } from "./deployment.server";
8+
import { recordDeploymentOutcome } from "./recordDeploymentOutcome.server";
89

910
export class TimeoutDeploymentService extends BaseService {
1011
public async call(id: string, fromStatus: string, errorMessage: string) {
@@ -48,6 +49,16 @@ export class TimeoutDeploymentService extends BaseService {
4849
},
4950
});
5051

52+
recordDeploymentOutcome({
53+
status: "TIMED_OUT",
54+
deploymentFriendlyId: deployment.friendlyId,
55+
organizationId: deployment.environment.project.organizationId,
56+
projectId: deployment.environment.projectId,
57+
environmentId: deployment.environmentId,
58+
environmentType: deployment.environment.type,
59+
reason: errorMessage,
60+
});
61+
5162
const deploymentService = new DeploymentService();
5263
await deploymentService
5364
.appendToEventLog(deployment.environment.project, timedOutDeployment, [

0 commit comments

Comments
 (0)