Skip to content

Commit 3218843

Browse files
committed
test(run-engine): cover cross-table cancel cascade in the task_run_v2 mixed window
A cuid parent (TaskRun) with a ksuid child (task_run_v2): cancelling the parent must cascade to the child in the other table. Fails against the old table-bound childRuns relation, passes with the cross-table findRuns lookup.
1 parent ef54cb9 commit 3218843

1 file changed

Lines changed: 114 additions & 0 deletions

File tree

internal-packages/run-engine/src/engine/tests/cancelling.test.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { containerTest, assertNonNullable } from "@internal/testcontainers";
22
import { trace } from "@internal/tracing";
3+
import { isKsuidId, RunId } from "@trigger.dev/core/v3/isomorphic";
34
import { expect } from "vitest";
45
import { RunEngine } from "../index.js";
56
import { setTimeout } from "timers/promises";
@@ -227,6 +228,119 @@ describe("RunEngine cancelling", () => {
227228
}
228229
);
229230

231+
containerTest(
232+
"Cancelling a parent cascades to a child in the OTHER run table (cross-table mixed window)",
233+
async ({ prisma, redisOptions }) => {
234+
const authenticatedEnvironment = await setupAuthenticatedEnvironment(prisma, "PRODUCTION");
235+
236+
const engine = new RunEngine({
237+
prisma,
238+
worker: {
239+
redis: redisOptions,
240+
workers: 1,
241+
tasksPerWorker: 10,
242+
pollIntervalMs: 100,
243+
},
244+
queue: {
245+
redis: redisOptions,
246+
masterQueueConsumersDisabled: true,
247+
processWorkerQueueDebounceMs: 50,
248+
},
249+
runLock: {
250+
redis: redisOptions,
251+
},
252+
machines: {
253+
defaultMachine: "small-1x",
254+
machines: {
255+
"small-1x": {
256+
name: "small-1x" as const,
257+
cpu: 0.5,
258+
memory: 0.5,
259+
centsPerMs: 0.0001,
260+
},
261+
},
262+
baseCostInCents: 0.0001,
263+
},
264+
tracer: trace.getTracer("test", "0.0.0"),
265+
});
266+
267+
try {
268+
const parentTask = "parent-task";
269+
const childTask = "child-task";
270+
await setupBackgroundWorker(engine, authenticatedEnvironment, [parentTask, childTask]);
271+
272+
// Parent gets a cuid id (-> TaskRun); child gets a ksuid id
273+
// (-> task_run_v2). This is exactly the hierarchy a runTableV2 flip
274+
// creates while a pre-flip parent is still live.
275+
const parentId = RunId.generate();
276+
const childId = RunId.generateKsuid();
277+
278+
const parentRun = await engine.trigger(
279+
{
280+
number: 1,
281+
friendlyId: parentId.friendlyId,
282+
environment: authenticatedEnvironment,
283+
taskIdentifier: parentTask,
284+
payload: "{}",
285+
payloadType: "application/json",
286+
context: {},
287+
traceContext: {},
288+
traceId: "tp",
289+
spanId: "sp",
290+
workerQueue: "main",
291+
queue: `task/${parentTask}`,
292+
isTest: false,
293+
tags: [],
294+
},
295+
prisma
296+
);
297+
298+
const childRun = await engine.trigger(
299+
{
300+
number: 1,
301+
friendlyId: childId.friendlyId,
302+
environment: authenticatedEnvironment,
303+
taskIdentifier: childTask,
304+
payload: "{}",
305+
payloadType: "application/json",
306+
context: {},
307+
traceContext: {},
308+
traceId: "tc",
309+
spanId: "sc",
310+
workerQueue: "main",
311+
queue: `task/${childTask}`,
312+
isTest: false,
313+
tags: [],
314+
parentTaskRunId: parentRun.id,
315+
},
316+
prisma
317+
);
318+
319+
// The hierarchy genuinely straddles the two physical run tables.
320+
expect(isKsuidId(parentRun.id)).toBe(false);
321+
expect(isKsuidId(childRun.id)).toBe(true);
322+
323+
// Cancel the (queued) parent. Pre-fix, cancelRun read children through
324+
// the table-bound childRuns relation, which cannot see the v2 child, so
325+
// the cascade skipped it and it kept its place in the queue. Post-fix,
326+
// the cross-table findRuns finds the child and cancels it too.
327+
await engine.cancelRun({
328+
runId: parentRun.id,
329+
completedAt: new Date(),
330+
reason: "Cancelled by the user",
331+
});
332+
333+
// The child cancellation is enqueued as a job; give the worker a moment.
334+
await setTimeout(1000);
335+
336+
const childData = await engine.getRunExecutionData({ runId: childRun.id });
337+
expect(childData?.run.status).toBe("CANCELED");
338+
} finally {
339+
await engine.quit();
340+
}
341+
}
342+
);
343+
230344
containerTest("Cancelling a run (not executing)", async ({ prisma, redisOptions }) => {
231345
//create environment
232346
const authenticatedEnvironment = await setupAuthenticatedEnvironment(prisma, "PRODUCTION");

0 commit comments

Comments
 (0)