You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Required for v1.0.0 (#93): ship a small, opt-in transport retry helper with per-request controls that work across the SDK and consumer adapters. Keep the default REST request path single-attempt, and preserve consumer ownership of credentials and response caches.
This resolves the scope question from #81: share reusable retry mechanics in @sentry/api; consumers supply their authentication, instrumentation, and application-specific policies. Progressive-accuracy queries remain a separate capability.
Why this belongs in v1
CLI, MCP, and frontend consumers currently implement their own retry behavior. MCP #1283 supplies prior art for bounded GET retries on transient gateway errors. CLI #1649 demonstrates why retries and cache behavior also need per-call controls for the issue link/unlink flow (#1559):
A Sentry App link calls the external provider before storing the association in Sentry. A failure after the provider acted can leave nothing stored to deduplicate a subsequent POST. expectedExternalIssueUrl protects an already-stored association; it does not guarantee exactly-once callbacks. This mutation must not be replayed automatically.
Preflight reads must use current associations. A stale cached response can make unlink incorrectly report that an association is already absent. These reads need to bypass both cache lookup and storage without changing defaults for other calls.
Today CLI #1649 captures these controls inside its custom fetch. It does not pass a retry option to the SDK, and its local cache checks the wrapper's options rather than the incoming Request.cache. Adding SDK retries above that adapter, or only forwarding the standard cache option, would not preserve the intended guarantees. Adoption must exercise the full composed request path.
Required contract
Export an opt-in retry helper that composes with an injected transport. Initially retry only GET/HEAD on 502/503/504; mutations must not become retryable implicitly. Calls that do not opt in retain the existing single-attempt behavior.
Provide bounded retry counts and backoff, with documented defaults. Preserve method, body, headers, and cancellation. Abort must stop in-flight work and pending backoff without scheduling another attempt.
Define typed per-call overrides and their precedence over client defaults. Overrides must be isolated across concurrent calls and must not mutate process-wide or client-wide settings. Settle the exported helper/options shape before the v1 API freeze; the earlier withRetry sketch was not a frozen API.
Provide an explicit no-replay control (retry: false in CLI #1649). For a dispatched resource request it must allow at most one attempt across the SDK and the supported adapter composition, including suppressing reactive 401 refresh-and-replay. Proactive credential refresh before dispatch remains consumer-owned and is distinct from replaying the resource request. Document the adapter contract; the SDK cannot disable retries hidden inside an arbitrary custom transport.
Make retry ownership explicit during adoption. Replace or disable the equivalent consumer retry loop when enabling the shared helper; do not multiply budgets by nesting loops. Retained authentication or application-level retry policies must compose deliberately and honor the no-replay control, including re-execution by query frameworks. Pagination and progressive accuracy remain distinct domain mechanisms, not additional transport retry budgets.
Preserve the standard per-call cache: "no-store" option through the SDK and adapters. Consumer-owned response caches must honor it by skipping both lookup and storage for that request. It does not flush existing entries or replace mutation invalidation. Keep persistent storage, TTL policy, cache invalidation, and CLI --fresh behavior with consumers; this work does not introduce an SDK response cache.
Preserve the actual final HTTP response or transport failure through the existing error contract. In particular, a final-attempt 401 must remain a 401 instead of becoming an internal retry-exhaustion error. Credential storage/refresh, login guidance, UI messages, and CLI exit codes remain consumer responsibilities.
Validation and adoption evidence
SDK contract tests cover eligible GET/HEAD failures and budgets, mutation non-replay, per-call disabling, concurrent override isolation, cancellation during fetch/backoff, and final-response/error preservation.
Test cache-option propagation through both Request and (input, init) adapter forms. Seed a stale consumer cache and verify that a no-store preflight fetches fresh data without writing it back or changing subsequent calls' defaults.
Demonstrate an integrated CLI preflight and Sentry App mutation through generated SDK operations. Simulate a provider effect followed by HTTP failure, timeout, or connection loss and verify that the client does not replay the mutation. Include reactive 401 handling and confirm that no second SDK/consumer retry loop remains. Reuse the behavior introduced by CLI #1649; that PR alone is not SDK adoption evidence.
Compile and exercise the public package helper in a clean consumer with an injected transport, and document how existing CLI/MCP/frontend retry policies compose or are replaced. Link implementation and consumer validation from v1.0.0 #93, distinguishing mocked contract checks from real deployment verification. A full rewrite of every consumer is not required.
Remaining design decisions
Exact public helper/options shape and how supported adapters receive per-call retry policy without encoding it as an HTTP header.
Default budget, delays, and jitter.
Whether selected network failures are included in v1. Cancellation must never be retried. Broader 500, 408, or 429/Retry-After policies are outside the minimum GET/HEAD gateway-retry contract and must not be inherited accidentally from the CLI implementation.
Goal
Required for v1.0.0 (#93): ship a small, opt-in transport retry helper with per-request controls that work across the SDK and consumer adapters. Keep the default REST request path single-attempt, and preserve consumer ownership of credentials and response caches.
This resolves the scope question from #81: share reusable retry mechanics in
@sentry/api; consumers supply their authentication, instrumentation, and application-specific policies. Progressive-accuracy queries remain a separate capability.Why this belongs in v1
CLI, MCP, and frontend consumers currently implement their own retry behavior. MCP #1283 supplies prior art for bounded GET retries on transient gateway errors. CLI #1649 demonstrates why retries and cache behavior also need per-call controls for the issue link/unlink flow (#1559):
expectedExternalIssueUrlprotects an already-stored association; it does not guarantee exactly-once callbacks. This mutation must not be replayed automatically.Today CLI #1649 captures these controls inside its custom
fetch. It does not pass a retry option to the SDK, and its local cache checks the wrapper's options rather than the incomingRequest.cache. Adding SDK retries above that adapter, or only forwarding the standard cache option, would not preserve the intended guarantees. Adoption must exercise the full composed request path.Required contract
GET/HEADon502/503/504; mutations must not become retryable implicitly. Calls that do not opt in retain the existing single-attempt behavior.withRetrysketch was not a frozen API.retry: falsein CLI #1649). For a dispatched resource request it must allow at most one attempt across the SDK and the supported adapter composition, including suppressing reactive 401 refresh-and-replay. Proactive credential refresh before dispatch remains consumer-owned and is distinct from replaying the resource request. Document the adapter contract; the SDK cannot disable retries hidden inside an arbitrary custom transport.cache: "no-store"option through the SDK and adapters. Consumer-owned response caches must honor it by skipping both lookup and storage for that request. It does not flush existing entries or replace mutation invalidation. Keep persistent storage, TTL policy, cache invalidation, and CLI--freshbehavior with consumers; this work does not introduce an SDK response cache.Validation and adoption evidence
Requestand(input, init)adapter forms. Seed a stale consumer cache and verify that a no-store preflight fetches fresh data without writing it back or changing subsequent calls' defaults.Remaining design decisions
500,408, or429/Retry-Afterpolicies are outside the minimum GET/HEAD gateway-retry contract and must not be inherited accidentally from the CLI implementation.