Skip to content

Commit 4038e6f

Browse files
committed
refactor: fold attribute docs into the telemetry constants, neverthrow cancel emission
Replaces the standalone DEPLOYMENT_TELEMETRY_ATTRIBUTES.md with short comments on the DeploymentTelemetryAttributes keys, and chains the canceled-lifecycle emission through the cancel ResultAsync pipeline instead of a fire-and-forget promise.
1 parent 6919caa commit 4038e6f

4 files changed

Lines changed: 48 additions & 60 deletions

File tree

apps/webapp/app/v3/DEPLOYMENT_TELEMETRY_ATTRIBUTES.md

Lines changed: 0 additions & 44 deletions
This file was deleted.

apps/webapp/app/v3/deploymentTelemetry.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,57 @@
11
import { BuildServerMetadata } from "@trigger.dev/core/v3";
22

3-
// Attribute names for the deployment telemetry events (see
4-
// DEPLOYMENT_TELEMETRY_ATTRIBUTES.md next to this file). This module is the single owner of these names — Axiom
5-
// queries, dashboards, and monitors reference them, so treat renames as
6-
// breaking changes.
3+
/**
4+
* Attribute names for the `deployment.lifecycle` and `deployment.initialized`
5+
* telemetry events (emitted by services/recordDeploymentLifecycle.server.ts).
6+
* This module is the single owner of these names — external queries,
7+
* dashboards, and monitors reference them, so treat renames as breaking.
8+
*
9+
* Query gotchas: dedup with `arg_max(_time, *) by deployment.id` (job retries
10+
* can double-emit); the span's `_time` is the deployment's createdAt, so a
11+
* TIMED_OUT event lands backdated by up to the full deploy timeout — monitor
12+
* windows must exceed it; phase durations are omitted (not zero) when a
13+
* boundary timestamp is missing, and `total_ms` excludes local-bundle's
14+
* pre-init client work (esbuild + upload) until the CLI reports timings.
15+
*/
716
export const DeploymentTelemetryAttributes = {
817
ORG_ID: "$trigger.org.id",
918
PROJECT_ID: "$trigger.project.id",
19+
// Project external ref ("proj_…")
1020
PROJECT_REF: "$trigger.project.ref",
1121
ENV_ID: "$trigger.env.id",
22+
// PRODUCTION / STAGING / PREVIEW / DEVELOPMENT
1223
ENV_TYPE: "$trigger.env.type",
24+
// Deployment friendly id — the dedup key
1325
DEPLOYMENT_ID: "deployment.id",
1426
VERSION: "deployment.version",
27+
// lifecycle: terminal status; initialized: initial status (PENDING/BUILDING)
1528
STATUS: "deployment.status",
29+
// status === DEPLOYED; CANCELED is excluded from failure rates
1630
SUCCESS: "deployment.success",
31+
// depot / native / local_bundle (see deriveBuildPath)
1732
BUILD_PATH: "deployment.build_path",
33+
// V1 / MANAGED (run engine)
1834
WORKER_TYPE: "deployment.worker_type",
1935
RUNTIME: "deployment.runtime",
36+
// Set at indexing; null for pre-index failures
2037
RUNTIME_VERSION: "deployment.runtime_version",
38+
// From x-trigger-cli-version at init; null for pre-column history
2139
CLI_VERSION: "deployment.cli_version",
2240
TRIGGERED_VIA: "deployment.triggered_via",
2341
COMMIT_SHA: "deployment.commit_sha",
42+
// error.* only on FAILED/TIMED_OUT; CANCELED uses canceled_reason
2443
ERROR_NAME: "deployment.error.name",
2544
ERROR_MESSAGE: "deployment.error.message",
2645
CANCELED_REASON: "deployment.canceled_reason",
46+
// createdAt → terminal (also the span's own duration)
2747
DURATION_TOTAL_MS: "deployment.duration.total_ms",
48+
// createdAt → startedAt; ≈0 when created directly in BUILDING (depot)
2849
DURATION_QUEUE_MS: "deployment.duration.queue_ms",
50+
// startedAt → installedAt; build-server paths only (depot never sets it)
2951
DURATION_INSTALL_MS: "deployment.duration.install_ms",
52+
// (installedAt ?? startedAt) → builtAt
3053
DURATION_BUILDING_MS: "deployment.duration.building_ms",
54+
// builtAt → terminal; for depot dominated by the server-side registry push
3155
DURATION_DEPLOYING_MS: "deployment.duration.deploying_ms",
3256
} as const;
3357

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

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,6 @@ export class DeploymentService extends BaseService {
239239
if (result.count === 0) {
240240
return errAsync({ type: "deployment_cannot_be_cancelled" as const });
241241
}
242-
// Fire-and-forget: telemetry must never affect the cancel result.
243-
void this.#recordCanceledLifecycle(deployment.id);
244242
return okAsync({ deployment });
245243
});
246244

@@ -253,6 +251,14 @@ export class DeploymentService extends BaseService {
253251
return this.getDeployment(authenticatedEnv.id, friendlyId)
254252
.andThen(validateDeployment)
255253
.andThen(cancelDeployment)
254+
.andThen(({ deployment }) =>
255+
this.#recordCanceledLifecycle(deployment.id)
256+
.orElse((error) => {
257+
logger.error("Failed to record canceled deployment lifecycle", { error });
258+
return okAsync(undefined);
259+
})
260+
.map(() => ({ deployment }))
261+
)
256262
.andThen(({ deployment }) =>
257263
this.appendToEventLog(deployment.environment.project, deployment, [
258264
{
@@ -479,9 +485,9 @@ export class DeploymentService extends BaseService {
479485

480486
// The cancel path only carries a narrow row selection, so re-fetch the full
481487
// row (post-update, status already CANCELED) for the lifecycle event.
482-
async #recordCanceledLifecycle(deploymentId: string) {
483-
try {
484-
const canceled = await this._prisma.workerDeployment.findFirst({
488+
#recordCanceledLifecycle(deploymentId: string) {
489+
return fromPromise(
490+
this._prisma.workerDeployment.findFirst({
485491
where: { id: deploymentId },
486492
include: {
487493
environment: {
@@ -492,8 +498,12 @@ export class DeploymentService extends BaseService {
492498
},
493499
},
494500
},
495-
});
496-
501+
}),
502+
(error) => ({
503+
type: "other" as const,
504+
cause: error,
505+
})
506+
).map((canceled) => {
497507
if (!canceled || canceled.status !== "CANCELED") return;
498508

499509
recordDeploymentLifecycle({
@@ -507,9 +517,7 @@ export class DeploymentService extends BaseService {
507517
environmentType: canceled.environment.type,
508518
},
509519
});
510-
} catch (error) {
511-
logger.error("Failed to record canceled deployment lifecycle", { deploymentId, error });
512-
}
520+
});
513521
}
514522

515523
private getDeployment(environmentId: string, friendlyId: string) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ type EnvironmentInfo = {
4949
* `deployment.lifecycle` span, backdated to span the deployment's real
5050
* lifetime (createdAt → terminal) and carrying per-phase durations as
5151
* attributes. This is THE per-deployment analytics event: build-path
52-
* comparison dashboards and monitors are built on it (see
53-
* ../deploymentTelemetry.ts and DEPLOYMENT_TELEMETRY_ATTRIBUTES.md for the attribute contract).
52+
* comparison dashboards and monitors are built on it (the attribute contract
53+
* lives in ../deploymentTelemetry.ts).
5454
*
5555
* Call exactly once per terminal transition, only after a guarded status
5656
* write confirmed this caller won the transition. Emitted on ROOT_CONTEXT

0 commit comments

Comments
 (0)