Skip to content

fix(cloud): re-send a flow submit whose response was lost - #226

Merged
finalerock44 merged 2 commits into
devfrom
fix/retry-submit
Oct 16, 2026
Merged

finalerock44 merged 2 commits into
devfrom
fix/retry-submit

Conversation

@finalerock44

Copy link
Copy Markdown
Contributor

When the API stalls, a dcd cloud submit can wait 300 s and then get a 502 from Railway's edge. The CLI can't tell whether the run was created, so it failed the command even when the run went ahead (dcd#1617).

The API now answers a repeat of the same submit (same body, same upload id) with the run it already created, or a 409 while that run is still being created, and never creates a second run or charge. So the CLI sends a submit again while its outcome is unknown:

  • submitWithRetry (services/flow-submit.service.ts) re-sends the same body on a 409/500/502/503/504 or on any transport failure (network error, timeout, a body cut off), waiting 2 s and then up to 30 s between attempts, about three minutes in all. The flow zip is not uploaded again.
  • Each attempt has a 90 s timeout, well under the 300 s at which Railway's edge cuts it with a 502.
  • The multipart fallback for an API without the client-direct endpoint runs only when the first attempt 404s or 405s. A 404 after a retry comes from an API that took an earlier attempt.
  • dcd cloud prints one warning per retry (not in --json); dcd-mcp logs to stderr. Both record submit_attempts on the lifecycle telemetry event.
  • enhanceFetchError keeps the undici cause, so a timeout, a reset and a DNS failure no longer all read as "fetch failed".

No new flags: --retry already means re-running failed tests.

What & why

Type of change

  • fix — bug fix
  • feat — new feature
  • perf — performance improvement
  • refactor — code change that's neither a fix nor a feature
  • docs — documentation only
  • chore / ci / build / test — tooling, no user-facing change
  • Breaking change (title has ! or PR notes a BREAKING CHANGE:)

Checklist

  • PR title follows the Conventional Commits format (see comment above)
  • pnpm lint passes
  • pnpm typecheck passes
  • pnpm build passes
  • I have not bumped the version or edited CHANGELOG.md (release-please handles this)
  • I have signed the CLA (the bot will prompt on first contribution)
  • Docs / README.md / STYLE_GUIDE.md updated if behaviour or output changed

How to test

When the API stalls, a `dcd cloud` submit can wait 300 s and then get a
502 from Railway's edge. The CLI can't tell whether the run was created,
so it failed the command even when the run went ahead (dcd#1617).

The API now answers a repeat of the same submit (same body, same upload
id) with the run it already created, or a 409 while that run is still
being created, and never creates a second run or charge. So the CLI
sends a submit again while its outcome is unknown:

- submitWithRetry (services/flow-submit.service.ts) re-sends the same
  body on a 409/500/502/503/504 or on any transport failure (network
  error, timeout, a body cut off), waiting 2 s and then up to 30 s
  between attempts, about three minutes in all. The flow zip is not
  uploaded again.
- Each attempt has a 90 s timeout, well under the 300 s at which
  Railway's edge cuts it with a 502.
- The multipart fallback for an API without the client-direct endpoint
  runs only when the first attempt 404s or 405s. A 404 after a retry
  comes from an API that took an earlier attempt.
- `dcd cloud` prints one warning per retry (not in --json); dcd-mcp logs
  to stderr. Both record `submit_attempts` on the lifecycle telemetry
  event.
- enhanceFetchError keeps the undici cause, so a timeout, a reset and a
  DNS failure no longer all read as "fetch failed".

No new flags: `--retry` already means re-running failed tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@finalerock44 finalerock44 self-assigned this Oct 16, 2026
Comment thread src/commands/cloud.ts Outdated
Comment thread src/commands/cloud.ts Outdated
…empts

Review on #226:

- Every retry reused the auth resolved at the start of the command,
  and the retries can outlast a `dcd login` access token. The next
  attempt then got a non-retryable 401, possibly after an earlier
  attempt had already created the run. Each attempt now calls
  refreshAuth first, as the poll loops do. A session that can't be
  refreshed (definitive SessionRefreshError, or no stored session) is
  not retried.
- `submit_attempts` was only recorded on success, so `command failed`
  never carried it. That is the worst-stall case it exists to measure.
  submitWithRetry now calls onAttempt before each attempt, and both
  `dcd cloud` and dcd-mcp record the count there.

Also bounds the worst case. No attempt starts more than 5 minutes after
the first. With every attempt timing out at 90 s the retries could
otherwise hold the command for about 16 minutes; now the worst case is
about 6.5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Oct 16, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

@finalerock44
finalerock44 merged commit f4db8f9 into dev Oct 16, 2026
13 checks passed
@finalerock44
finalerock44 deleted the fix/retry-submit branch October 16, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant