Skip to content

fix(core): retry transient fetch network errors and buffer compressed multipart payloads - #602

Draft
jhssilva wants to merge 1 commit into
masterfrom
hugo.silva/fix-sourcemap-upload-retries
Draft

jhssilva wants to merge 1 commit into
masterfrom
hugo.silva/fix-sourcemap-upload-retries

Conversation

@jhssilva

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes two client-side issues in @dd/core/helpers/request surfaced during high-volume sourcemap uploads in web-ui (companion concurrency PR: https://github.com/ddoghq/web-ui/pull/28126):

  1. Retry transient fetch() network errors (ECONNRESET, EPIPE, ETIMEDOUT, UND_ERR_*):

    • Previously, doRequest() wrapped both getData() and await fetchImpl(...) in a single try/catch that called bail(error).
    • When fetch() rejected with TypeError: fetch failed (wrapping ECONNRESET, EPIPE, ETIMEDOUT, or UND_ERR_SOCKET), doRequest() called bail(error) on attempt 1, skipping all NB_RETRIES (5) retries and failing the upload immediately with status_code:unknown.
    • doRequest() now re-throws transient fetch network errors so async-retry retries them with backoff, while still bailing immediately on getData() errors, AbortSignal timeouts (AbortError / TimeoutError), and non-network TypeErrors (such as locked/disturbed streams).
  2. Materialize compressed payloads in createRequestData() before opening the HTTP request:

    • Previously, createRequestData() returned a lazy req.body.pipeThrough(new CompressionStream('gzip')) stream. When passed to fetch(), Undici immediately sent the HTTP request headers and the 10-byte gzip header (network.bytes_read: 10)—starting the intake edge's 30s/60s request-body receive timers—before the file-backed blobs were read from disk or compressed on Node's libuv threadpool. Under high concurrency, streams queued behind disk/zlib work sent 0 body bytes after the 10-byte gzip header for 60s and timed out with HTTP 408 (response_flags: SI, stream_idle_timeout).
    • createRequestData() now buffers the compressed payload in memory and sets Content-Length before returning, ensuring disk reads and gzip compression complete before the HTTP request headers are sent on the wire.

Related Links

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