Skip to content

Commit 0068a8e

Browse files
committed
fix(worker): recover stalled workflow steps
1 parent 9bb842b commit 0068a8e

19 files changed

Lines changed: 2218 additions & 31 deletions

apps/worker/src/lib/cancel-run.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,31 @@ describe("cancelRun", () => {
213213
});
214214
});
215215

216+
it("runs an explicit final fence before releasing the cancelling owner", async () => {
217+
const runRegistry = registry();
218+
const beforeRelease = vi.fn().mockResolvedValue(undefined);
219+
220+
await expect(cancelRunDetailed(
221+
"PROJ-1",
222+
{ ownerToken: "owner-a", runId: "run-1" },
223+
runRegistry,
224+
undefined,
225+
undefined,
226+
undefined,
227+
undefined,
228+
beforeRelease,
229+
)).resolves.toMatchObject({ cancelled: true, released: true });
230+
231+
expect(beforeRelease).toHaveBeenCalledWith(expect.objectContaining({
232+
subjectKey: "ticket:jira:PROJ-1",
233+
ownerToken: "owner-a",
234+
runId: "run-1",
235+
}));
236+
expect(beforeRelease.mock.invocationCallOrder[0]).toBeLessThan(
237+
vi.mocked(runRegistry.releaseCancellation).mock.invocationCallOrder[0],
238+
);
239+
});
240+
216241
it("records the cancellation reason best-effort after a confirmed cancel", async () => {
217242
const runRegistry = registry();
218243
await expect(cancelRun(

apps/worker/src/lib/cancel-run.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ export interface ObservedRunClaim {
2323

2424
export type CancelRunTarget = string | ObservedRunClaim;
2525

26+
export type CancelBeforeRelease = (owner: {
27+
subjectKey: string;
28+
ownerToken: string;
29+
runId: string | null;
30+
}) => Promise<void>;
31+
2632
/**
2733
* Result of a cancellation attempt. `alreadyTerminal` distinguishes a run
2834
* that was genuinely still in flight and got cancelled by this call from one
@@ -102,6 +108,7 @@ export async function cancelRunDetailed(
102108
targetColumn?: IssueTrackerMoveTarget,
103109
onReleased?: (subjectKey: string) => Promise<void> | void,
104110
reason?: string,
111+
beforeRelease?: CancelBeforeRelease,
105112
): Promise<CancelRunResult> {
106113
const subjectKey = ticketSubjectKey("jira", ticketKey);
107114
const confirmTicketMove = issueTracker && targetColumn
@@ -125,7 +132,7 @@ export async function cancelRunDetailed(
125132
target,
126133
runRegistry,
127134
onReleased,
128-
confirmTicketMove,
135+
beforeRelease ?? confirmTicketMove,
129136
reason,
130137
);
131138
}

0 commit comments

Comments
 (0)