Skip to content

Commit 26871d5

Browse files
d-csclaude
andcommitted
fix(run-ops split): gate topology split on the opt-in flag and tighten diagnostics
- gate runOpsTopology splitEnabled on RUN_OPS_SPLIT_ENABLED so provisioning both DSNs before flipping the flag cannot open a second pool or route writes ahead of the distinct-DB sentinel - rethrow the original UnclassifiableRunId in the cross-seam guard so its value/valueLength keep reflecting the real waitpoint id - log run-found-but-environment-unresolved distinctly from missing-run - correct the RUN_OPS_DATABASE_URL doc comment (Prisma datasource, not the webapp runtime pool) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 99643f8 commit 26871d5

4 files changed

Lines changed: 13 additions & 13 deletions

File tree

apps/webapp/app/db.server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ export function selectRunOpsTopology(
237237
// singletons use (captureInfrastructureErrors(tagDatasource(role, raw))).
238238
const runOpsTopology: RunOpsTopology = singleton("runOpsTopology", () => {
239239
const newUrl = env.TASK_RUN_DATABASE_URL;
240-
const splitEnabled = !!newUrl && !!env.TASK_RUN_LEGACY_DATABASE_URL;
240+
// Gate on the opt-in flag too: the distinct-DB sentinel only runs when the flag is on.
241+
const splitEnabled = env.RUN_OPS_SPLIT_ENABLED && !!newUrl && !!env.TASK_RUN_LEGACY_DATABASE_URL;
241242

242243
return selectRunOpsTopology(
243244
{

apps/webapp/app/env.server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ const EnvironmentSchema = z
129129
// Explicit positive opt-in. Split behavior is unreachable unless this is true
130130
// AND the distinct-DB sentinel confirms the two URLs are physically distinct DBs.
131131
RUN_OPS_SPLIT_ENABLED: BoolEnv.default(false),
132-
// Canonical URL for the dedicated run-ops DB. Takes precedence over TASK_RUN_DATABASE_URL.
132+
// Datasource URL for the dedicated run-ops Prisma schema (migrations/generation).
133+
// The webapp runtime pool is driven by TASK_RUN_DATABASE_URL, not this var.
133134
RUN_OPS_DATABASE_URL: z
134135
.string()
135136
.refine(isValidDatabaseUrl, "RUN_OPS_DATABASE_URL is invalid")

apps/webapp/app/v3/eventRepository/index.server.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,12 @@ async function findRunForEventCreation(runId: string) {
308308
);
309309

310310
if (!environment) {
311+
// Run exists but its environment could not be resolved (e.g. a lagging replica
312+
// under split); distinguish this from a genuinely missing run.
313+
logger.warn("Run found but environment unresolved for event creation", {
314+
runId,
315+
runtimeEnvironmentId: foundRun.runtimeEnvironmentId,
316+
});
311317
return null;
312318
}
313319

apps/webapp/app/v3/runOpsMigration/crossSeamGuard.server.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ownerEngine, UnclassifiableRunId } from "@trigger.dev/core/v3/isomorphic";
1+
import { ownerEngine } from "@trigger.dev/core/v3/isomorphic";
22
import { isSplitEnabled } from "./splitMode.server";
33
import type {
44
CrossSeamGuardDecision,
@@ -56,16 +56,8 @@ export function selectStoreForWaitpoint(
5656

5757
const classify = deps?.classify ?? ownerEngine;
5858

59-
let residency: RunOpsResidency;
60-
try {
61-
residency = classify(input.waitpointId);
62-
} catch (error) {
63-
// Loud on ambiguity: rethrow with context, never catch-and-default.
64-
if (error instanceof UnclassifiableRunId) {
65-
throw new UnclassifiableRunId(`${input.waitpointId} (routeKind=${input.routeKind})`);
66-
}
67-
throw error;
68-
}
59+
// Loud on ambiguity: classify throws UnclassifiableRunId with the real id; never catch-and-default.
60+
const residency: RunOpsResidency = classify(input.waitpointId);
6961

7062
const pinnedReason = applyPinningRules(input);
7163
const store: StoreTarget = pinnedReason ? "legacy" : storeForResidency(residency);

0 commit comments

Comments
 (0)