feat: retry transient 5xx errors in withSpinner#242
Draft
bukinoshita wants to merge 1 commit intomainfrom
Draft
Conversation
Add opt-in retry support for transient server-side errors (internal_server_error, service_unavailable, gateway_timeout) in the withSpinner retry loop, alongside the existing rate_limit_exceeded handling. - Extract isTransientError predicate into src/lib/is-transient-error.ts - Change withSpinner first param from string to SpinnerMessages object with optional retryTransient flag - Enable retryTransient for safe read operations (runGet, runList) and idempotent writes (template update, template publish) - Keep retryTransient disabled for non-idempotent commands (create, delete, send, batch) to avoid duplicate side effects - Update all direct withSpinner callers to use the new object signature - Add tests for transient retry behavior and isTransientError predicate Co-authored-by: Bu Kinoshita <bukinoshita@users.noreply.github.com>
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.
Summary
Resolves BU-639: Template automation exits on transient Resend 5xx failures.
The
withSpinner()retry wrapper previously only retriedrate_limit_exceeded(HTTP 429) errors. Transient server-side 5xx responses (internal_server_error,service_unavailable,gateway_timeout) caused immediate command failure — problematic for CI jobs and agent-driven template management.Changes
src/lib/is-transient-error.ts— New utility predicate that identifies transient 5xx-class error names from the Resend SDK.src/lib/spinner.ts— ChangedwithSpinnerfirst parameter from a plainstringto aSpinnerMessagesobject with an optionalretryTransientflag. When enabled, transient errors are retried with the same exponential backoff policy as rate limits.src/lib/actions.ts— EnabledretryTransientby default for safe read operations (runGet,runList). Added opt-inretryTransientfield torunWriteconfig. LeftrunCreateandrunDeletewithout transient retries to avoid duplicate side effects on non-idempotent operations.src/commands/templates/update.tsandsrc/commands/templates/publish.ts— Opted into transient retries since these are idempotent write operations.withSpinnercallers (emails/send.ts,emails/batch.ts,emails/receiving/attachment.ts,contacts/update-topics.ts) — Updated to use the new object signature. Attachment fetch getsretryTransient: true(read-only); send/batch/update-topics do not (non-idempotent).Testing
tests/lib/is-transient-error.test.tswith 6 tests covering all transient names plus negative cases.withSpinner retry on transient 5xx errorsdescribe block intests/lib/spinner.test.tswith 6 tests:retryTransient: trueretryTransientis not setrate_limit_exceededregardless ofretryTransientflagLinear Issue: BU-639
Summary by cubic
Add opt-in retries for transient 5xx errors in
withSpinnerto make read paths and idempotent template writes resilient to brief outages. Addresses BU-639 by preventing failures oninternal_server_error,service_unavailable, andgateway_timeout.New Features
withSpinnernow accepts{ loading, retryTransient? }; always retriesrate_limit_exceeded, and whenretryTransientis true, also retries transient 5xx with the same backoff/retry-afterlogic.retryTransient: trueforrunGetandrunList; optional onrunWrite(enabled fortemplates:updateandtemplates:publish; left off forcreate,delete,emails:send,emails:batch; enabled for read-onlyemails:receiving:attachment).isTransientErrorutility.Migration
withSpinner('message', ...)withwithSpinner({ loading: 'message' }, ...).retryTransient: true; keep it off for non-idempotent writes.runGet/runListare used (they now retry transient errors by default).Written for commit 1628223. Summary will update on new commits.