fix: default timeout on outbound fetch calls - #392
Open
hugo-ccabral wants to merge 2 commits into
Open
Conversation
Nothing bounded how long an outbound fetch could hang. withInflightTimeout only freed the dedup-cache Map slot on a stuck promise -- the real fetch kept running abandoned, pinning isolate memory until exceededMemory killed the worker (514 crashes/24h on one storefront). This aborts the request itself via AbortSignal.timeout, composed with any caller-supplied signal, wired into createInstrumentedFetch (per-integration + per-call override) and every raw fetch call site that bypassed it (VTEX, Magento, Resend, Shopify, fonts). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2 tasks
…apper A future dev can still bypass fetchSafe/vtexFetch/magentoFetch/etc. by typing bare fetch(), silently losing the timeout. Adds a Biome noRestrictedGlobals override banning the fetch global in apps-vtex/apps-magento/apps-resend/ apps-shopify/apps-website (excluding client-side hooks and tests), pointing at the sanctioned client. The ban also catches `typeof fetch` in type positions, so introduces a FetchFn alias (blocks/src/sdk/fetchTimeout.ts, exported from sdk/index.ts) to replace those annotations. Also fixes a real gap the rule caught: apps-vtex/utils/sitemap.ts's fetchImpl defaulted to raw fetch, same unbounded-hang risk as the other call sites fixed earlier on this branch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
nicacioliveira
approved these changes
Jul 24, 2026
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
fetch()could hang.withInflightTimeoutonly freed the dedup-cache Map slot on a stuck promise — the underlying fetch kept running abandoned, pinning isolate memory untilexceededMemorykilled the worker (514 crashes/24h observed on one storefront).packages/blocks/src/sdk/fetchTimeout.ts:withFetchTimeout()/withTimeoutSignal(), using nativeAbortSignal.timeout()composed withAbortSignal.any()so a caller-supplied signal is never dropped. Default 10s (DEFAULT_FETCH_TIMEOUT_MS).createInstrumentedFetch(the shared VTEX/Shopify chokepoint) astimeoutMs, overridable per-integration at creation and per-call viainit.timeoutMs.fetch()call site that bypassed instrumentation: VTEX_fetchfallback +fetchSafe/fetchAPI, Magento'smagentoFetch, Resend'ssendEmail, Shopify'screateGraphqlClientfallback, and the Google Fonts loader.Out of scope (flagged, not fixed here)
abTesting.ts'sproxyToFallbackstreams the full incoming request body (duplex: "half") to a fallback origin — a blanket default risks breaking legitimate large uploads and needs its own design pass.useCart,useUser, etc.) andinvoke.ts— client-side fetches to the site's own origin, not the server-side memory-pinning failure mode this fixes.Test plan
bun run --filter='./packages/blocks' typecheckand all touched packages typecheck cleanbun run teston blocks, apps-vtex, apps-magento, apps-resend, apps-website, apps-shopify — all pass (blocks' 23 pre-existing URLPattern failures confirmed unrelated viagit stash)apps-resend/send.test.ts's exacttoHaveBeenCalledWithassertion to allow the newsignalfield🤖 Generated with Claude Code
Summary by cubic
Add a default 10s timeout to all outbound fetch calls to stop hung requests from pinning memory and crashing workers. The timeout uses
AbortSignal.timeout()and composes with any callersignal.Bug Fixes
@decocms/blockshelpers:withFetchTimeout(),withTimeoutSignal(),DEFAULT_FETCH_TIMEOUT_MS = 10_000, and aFetchFnalias.createInstrumentedFetchwithtimeoutMs(per-integration) andinit.timeoutMs(per-call).apps-vtex(incl. sitemap),apps-magento,apps-resend,apps-shopify, andapps-website(Google Fonts). Added Biome rule to ban barefetchin commerce packages. Updated Resend test to accept asignal.Migration
timeoutMs(set to0/Infinityor a higher value).Written for commit 70833a6. Summary will update on new commits.