Give every job of one graceful cancel the same deadline
cancelInternal read Date.now() per job, so two running jobs could get cancel_at values a millisecond apart. The alarm for the earlier deadline then stopped only the first job, and the runtime test that cancels two running jobs failed now and then. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEy3wQ4DbP2VQUmrcNhTKn
- CI / Typecheck and bundlesuccess
- CI / Unit tests (1/2)success
- CI / Unit tests (2/2)success
- End-to-end / End-to-end (agent reviews, tasks, Today)success
- End-to-end / End-to-end (git, PRs, Actions)success
- End-to-end / End-to-end (large pushes)success
- End-to-end / End-to-end (passkeys, registry, email)success
- End-to-end / End-to-end (real histories)success
- End-to-end / End-to-end (runner Docker)success
- End-to-end / End-to-end (security)success
1 file changed+2−1
modifiedapps/diffinery/src/repo/actions.ts+2−1View file
| @@ -2115,9 +2115,10 @@ | ||
| 2115 | 2115 | const run = this.runRow(runId); |
| 2116 | 2116 | if (run.status === "completed") return; |
| 2117 | 2117 | this.sql.exec("UPDATE runs SET conclusion = 'cancelled', updated_at = ? WHERE id = ?", now(), run.id); |
| 2118 | + // One cancel, one deadline: the jobs it lets run their after-cancel steps all end together. | |
| 2119 | + const at = Date.now(); | |
| 2118 | 2120 | for (const j of this.sql.exec<JobRow>("SELECT * FROM jobs WHERE run_id = ? AND status != 'completed'", run.id).toArray()) { |
| 2119 | 2121 | if (graceful && !j.cancel_at && j.status === "in_progress" && !j.labels && j.container && !j.container.startsWith("self-hosted:")) { |
| 2120 | - const at = Date.now(); | |
| 2121 | 2122 | this.sql.exec("UPDATE jobs SET cancel_at = ?, cancel_reason = ? WHERE id = ?", at, reason, j.id); |
| 2122 | 2123 | await this.stopContainer(j, true); |
| 2123 | 2124 | this.repo.alarmBy(at + CANCEL_STOP_MS); |