Repository navigation
Conversation
The receive timeout timer, re-armed on every XHR `progress` event, was meant to be cancelled by the `onDone` callback of `xhr.onProgress`, but DOM event streams never close: the timer stayed armed until it fired, `receiveTimeout` after the response. The connect timeout timer could likewise outlive its request. While armed, a timer keeps the XHR and its response reachable, so each response stayed in memory for up to the configured timeout. Stop both timers on `loadend`, dispatched once the request has ended (load, error, abort or timeout) and after the handlers of those events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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.
BrowserHttpClientAdapterarms a receive timeout timer on every XHRprogressevent, and relied on theonDonecallback ofxhr.onProgressto cancel it. DOM event streams never close, soonDoneis never called: after a request completes, its receive timer stays armed until it fires,receiveTimeoutlater. The connect timeout timer of a request is likewise left armed when noprogressevent cancels it (e.g. when the request fails early).While armed, the timer closure keeps the XHR and its response reachable, so every response stays in memory for up to
receiveTimeoutafter it has been delivered. We hit this in a Flutter web app that syncs a ~300 MB catalogue in pages of ~10 MB withreceiveTimeout: 30s: heap snapshots showed all pages still retained once written to the local database (~1 GB in the tab), held byBrowserHttpClientAdapter_fetch_watchReceiveTimeout_closure. Downloading many media files showed the same pattern.This PR stops both timers on the XHR
loadendevent, which is dispatched once a request has ended, whatever the outcome (load, error, abort or timeout). It is dispatched afterload,error,abortandtimeout, so the existing handlers of those events run first and timeout classification is unchanged. TheonDonecallback, which never runs, is removed.New Pull Request Checklist
mainbranch to avoid conflicts (via merge from master or rebase)CHANGELOG.mdin the corresponding packageAdditional context and info (if any)
Verification: the new browser test
plugins/web_adapter/test/timers_test.dartrecords the timers the adapter arms for a request (through a zone) and checks that none is still active once the response has been delivered. It fails onmain(one active timer left) and passes with this change. The wholeplugins/web_adaptersuite passes in Chrome (dart test -p chrome, 37 tests), anddart analyze --fatal-infos/dart formatare clean.The
diopackage web tests in Chrome, which run the shareddio_testsuites (timeouts, cancellation, downloads…) on this adapter, give the same result with and without this change: 193 passed, 1 skipped, 1 failed with an XHR connection error from the remote test server, identical onmain.Unverified: Firefox (not available on my machine);
loadendis part of the XHR standard and supported by all browsers dio targets.Timeout handling is a sensitive area per AGENTS.md: cc @cfug/dio-core.
Root-cause analysis (heap snapshots), implementation and test by Claude (Claude Code).