fix(deploy): release a settled idempotency key so redeploys aren't permanently blocked#5908
fix(deploy): release a settled idempotency key so redeploys aren't permanently blocked#5908TheodoreSpeaks wants to merge 1 commit into
Conversation
…rmanently blocked
Redeploying a workflow could fail forever with "Idempotency key was already used
for a different deployment request", with no way to clear it from the workflow.
The deploy orchestrator scopes one idempotency key to a whole request
(`idempotencyKey: params.requestId`) while the request hash is derived from
workflow state. That is fine when one request performs one deployment, but the
agent path issues several deployments per chat request: deploy, edit, redeploy.
The second deployment presents the same key with a new hash, so
prepareWorkflowDeployment took the conflict branch — and kept taking it, because
the key was never released.
Two problems, both in the same block:
- The request-hash comparison ran BEFORE the terminal-status check, so the
release path was unreachable whenever the hash differed. Its own comment
("a terminally failed or superseded attempt releases its idempotency key")
therefore never applied to the case that needed it.
- A completed (`active`) operation was not treated as settled at all, so a
successful deployment reserved its key permanently.
Reordered so the key is released whenever the prior attempt is settled
(`active`, `failed`, or `superseded`) and the request genuinely differs. A
conflict is now raised only when a *different* deployment is still in flight
(`pending`/`preparing`/`activating`), which is the ambiguous case idempotency
is meant to guard. True duplicate submissions (same key, same hash) still reuse
the existing operation and never redeploy.
Observed on staging: one chat request (58a47006) deployed three workflows, then
its redeploy of the first failed five times in a row with this error.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018asmKsWQ5Vi7T7wD9uHofz
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview
Adds four tests covering active/failed release with a different hash, unchanged conflict during activation, and duplicate reuse for completed Reviewed by Cursor Bugbot for commit af46917. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThis PR corrects deployment idempotency handling for request-scoped keys.
Confidence Score: 5/5The PR appears safe to merge, with settled and in-flight deployment states handled consistently by the revised idempotency logic. The workflow transaction serializes preparation, terminal statuses align with the new settled classification, same-hash duplicates remain reusable, and different in-flight requests still return a conflict. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Existing operation for idempotency key] --> B{Same request hash?}
B -->|Yes| C{Failed or superseded?}
C -->|No| D[Reuse existing operation]
C -->|Yes| E[Release key and create fresh operation]
B -->|No| F{Active, failed, or superseded?}
F -->|No| G[Return idempotency conflict]
F -->|Yes| E
Reviews (1): Last reviewed commit: "fix(deploy): release a settled idempoten..." | Re-trigger Greptile |
Symptom
Redeploying a workflow fails forever with:
It is not recoverable from the workflow — editing the workflow changes the request hash, which is precisely what keeps triggering it.
Root cause
The deploy orchestrator scopes one idempotency key to a whole request (
orchestration/deploy.ts:idempotencyKey: params.requestId), whilerequestHashis derived from workflow state.That holds when one request performs one deployment. The agent path breaks it: a single
/api/mothership/chatrequest deploys, edits, then redeploys. The second deployment presents the same key with a new hash, soprepareWorkflowDeploymenttook the conflict branch — and kept taking it, because the key was never released.Two defects in the same block:
activewasn't settled — a successfully completed operation reserved its key permanently.Evidence (staging)
One chat request
58a47006deployed three workflows:870c86b7…4c7600a2…c4f8bd85…It then tried to redeploy
870c86b7— same key, new hash — and failed five times (00:07:18 → 00:08:57), eachtoolName: "redeploy"→idempotency_conflict. The held row wasactive, so the key was never freed.Fix
Release the key whenever the prior attempt is settled (
active,failed, orsuperseded) and the request genuinely differs. Conflict is now raised only when a different deployment is still in flight (pending/preparing/activating) — the genuinely ambiguous case idempotency exists to guard.Duplicate-submission protection is unchanged: same key + same hash still reuses the existing operation and never redeploys.
Checks
bunx vitest run lib/workflows— 989 passed (54 files); 4 new cases, all 11 pre-existingdeployment-operationstests unchanged and greenbun run type-check— no new errors (7 pre-existing: better-auth +@daytonaio/sdk)bun run lint:check— clean🤖 Generated with Claude Code
https://claude.ai/code/session_018asmKsWQ5Vi7T7wD9uHofz