diff --git a/.server-changes/README.md b/.server-changes/README.md index 82716de98..2b0eeade3 100644 --- a/.server-changes/README.md +++ b/.server-changes/README.md @@ -38,6 +38,14 @@ Speed up batch queue processing by removing stalls and fixing retry race The body text (below the frontmatter) is a one-line description of the change. Keep it concise — it will appear in release notes. +### Writing guidance + +These entries are public-facing - they ship verbatim in user-visible release notes. A few rules to keep them clean: + +- **One sentence is usually enough.** The body is the bullet in the changelog. If you need a paragraph, you're probably describing the implementation rather than the change. +- **Describe behavior, not implementation.** Skip internal scopes, middleware names, library specifics, framework internals. Users care about what's different for them, not how it's wired. +- **Never name internal tools or infra.** Observability stacks, internal services, infra components, monitoring backends, CI surfaces, AWS specifics - none of these belong in user-facing notes. + ## Lifecycle 1. Engineer adds a `.server-changes/` file in their PR diff --git a/.server-changes/supervisor-compute-traceparent-forwarding.md b/.server-changes/supervisor-compute-traceparent-forwarding.md new file mode 100644 index 000000000..5d20c0869 --- /dev/null +++ b/.server-changes/supervisor-compute-traceparent-forwarding.md @@ -0,0 +1,6 @@ +--- +area: supervisor +type: improvement +--- + +Forward `traceparent` headers on outbound calls to the compute provider so distributed traces stay continuous across services. diff --git a/apps/supervisor/src/workloadManager/compute.ts b/apps/supervisor/src/workloadManager/compute.ts index 1c00f33aa..2c51b15f2 100644 --- a/apps/supervisor/src/workloadManager/compute.ts +++ b/apps/supervisor/src/workloadManager/compute.ts @@ -10,6 +10,7 @@ import { ComputeClient, stripImageDigest } from "@internal/compute"; import { extractTraceparent, getRunnerId } from "../util.js"; import type { OtlpTraceService } from "../services/otlpTraceService.js"; import { tryCatch } from "@trigger.dev/core"; +import { fromContext } from "../wideEvents/index.js"; type ComputeWorkloadManagerOptions = WorkloadManagerOptions & { gateway: { @@ -46,6 +47,20 @@ export class ComputeWorkloadManager implements WorkloadManager { gatewayUrl: opts.gateway.url, authToken: opts.gateway.authToken, timeoutMs: opts.gateway.timeoutMs, + // Forward the current wide-event scope's traceparent + request_id so the + // downstream service continues the same trace and joins its own wide + // events to ours. When called outside a wide-event scope (or when wide + // events are disabled), `fromContext` returns undefined and propagation + // is skipped. + getPropagationHeaders: () => { + const state = fromContext(); + if (!state) return {}; + const headers: Record = { "x-request-id": state.requestId }; + if (state.traceparent) { + headers.traceparent = state.traceparent; + } + return headers; + }, }); } diff --git a/internal-packages/compute/src/client.ts b/internal-packages/compute/src/client.ts index 97585345e..d6215678b 100644 --- a/internal-packages/compute/src/client.ts +++ b/internal-packages/compute/src/client.ts @@ -11,6 +11,13 @@ export type ComputeClientOptions = { gatewayUrl: string; authToken?: string; timeoutMs: number; + /** + * Called once per outbound request to collect cross-service correlation + * headers (e.g. `traceparent`, `x-request-id`) from the caller's current + * scope. The returned record is merged onto the outbound headers. Return + * `{}` (or omit the option) to skip propagation. + */ + getPropagationHeaders?: () => Record; }; export class ComputeClient { @@ -40,6 +47,14 @@ class HttpTransport { if (this.opts.authToken) { h["Authorization"] = `Bearer ${this.opts.authToken}`; } + const propagation = this.opts.getPropagationHeaders?.(); + if (propagation) { + for (const [key, value] of Object.entries(propagation)) { + if (value) { + h[key] = value; + } + } + } return h; }