pipeline-cmd: add --retries for transient connection errors - #1
Merged
Conversation
ps:exec-style commands intermittently fail even when the dyno is up: Heroku's exec-manager rejects the credential handshake, the SSH tunnel drops mid-session, or keepalives time out. All of these succeed on a plain re-run and show up more often under parallel load — exactly how pipeline-cmd runs heroku. Add an opt-in --retries=N flag that re-runs an app up to N extra times, with linearly increasing backoff, when its combined output matches one of those known-transient error messages. The pattern is deliberately narrow so genuine command failures are never retried, and a persistently failing app still emits its last error as its record. Default is 0, so existing behavior is unchanged. HEROKU_SCRIPTS_RETRY_DELAY overrides the 15s backoff unit; the tests set it to 0 to stay fast. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds an opt-in retry mechanism to pipeline-cmd to automatically re-run per-app Heroku commands when the output indicates a known transient dyno connection failure, with linear backoff between attempts.
Changes:
- Introduces
--retries=Ntopipeline-cmd, plusHEROKU_SCRIPTS_RETRY_DELAYto control backoff timing. - Implements retry logic via
heroku_for_app_with_retries, retrying only when output matches a transient-connection error pattern. - Adds Bats tests covering retry behavior, non-retry behavior for genuine failures, and flag validation; updates README/docs.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
bin/heroku-scripts |
Adds --retries flag parsing/validation and retry wrapper around per-app Heroku execution. |
test/heroku-scripts.bats |
Adds tests validating retry-until-success, default behavior, persistent transient failures, non-retry failures, and flag validation. |
README.md |
Documents --retries usage, behavior, and the idempotency caveat. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an opt-in
--retries=Nflag topipeline-cmdthat re-runs an app when its output matches a known transient connection error, with linearly increasing backoff (15s, 30s, …). Default is--retries=0— existing behavior is byte-for-byte unchanged.Why
ps:exec-style commands intermittently fail even when the dyno is up and running. Running an rpc across a ~200-app production stage surfaced three distinct flavors, all of which succeed on a plain re-run:Could not connect to dyno!— exec-manager rejects/times out the credential PUT (Establishing credentials... error)There was an error connecting to the dyno!— the SSH tunnel socket drops mid-session (ECONNRESET from the proxy)Connection to the dyno timed out!— missed keepalivesThese show up disproportionately under parallel load — exactly how
pipeline-cmdruns heroku — so today a big run reliably ends with a handful of apps whose record is a connection error rather than command output, and re-running the whole stage is the only recourse.How
TRANSIENT_CONNECTION_ERRORSpattern (the messages the heroku CLI'sps-execcode emits for connection-layer failures). Anything else is treated as a genuine command failure and is never retried.heroku_for_app_with_retrieswrapsheroku_for_app; the final attempt's output becomes the app's record either way, so a persistently failing app still surfaces its error. Each retry logs a notice to stderr so the data stream stays clean.HEROKU_SCRIPTS_RETRY_DELAYoverrides the 15s backoff unit; the tests set it to 0 to stay fast.--retriesshould only be used with idempotent commands.Testing
shellcheck bin/heroku-scripts install.shis clean (v0.11.0).🤖 Generated with Claude Code