parse only large transcript chunks off-isolate; deflake stream tests
test / unit + widget + golden + a11y (push) Failing after 27s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 24s
test / unit + widget + golden + a11y (push) Failing after 27s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 24s
The hang fix offloaded every transcript parse to Isolate.run, including the small per-poll appends. Spawning a one-shot isolate each tick is pure overhead and, under concurrent test load, the spawn+round-trip latency blew the streaming tests' fixed-delay window — transcript_reader_test flaked intermittently in the full suite. Only chunks >= 64KB now go off-isolate (the initial-tail case that actually janks a frame); small appends parse inline. The streaming tests poll until the expected items arrive instead of waiting a fixed delay, so they're robust regardless of parse latency or scheduler load. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -152,6 +152,11 @@ String _shortId(String uuid) => uuid.length >= 8 ? uuid.substring(0, 8) : uuid;
|
||||
/// stream incrementally.
|
||||
const _defaultInitialTailBytes = 256 * 1024;
|
||||
|
||||
/// Chunks at least this large are parsed in a background isolate; smaller
|
||||
/// ones parse inline. Streaming appends are small, so this keeps the
|
||||
/// off-thread parse to the initial-tail case that actually janks a frame.
|
||||
const _isolateParseThreshold = 64 * 1024;
|
||||
|
||||
/// Known major transcript versions.
|
||||
const _knownMajorVersions = {1, 2};
|
||||
|
||||
@@ -321,9 +326,12 @@ class TranscriptReader {
|
||||
}
|
||||
if (controller.isClosed) return;
|
||||
|
||||
// Parse off the UI isolate — the initial chunk can be sizeable and
|
||||
// JSON-decoding it on the main thread would jank the frame.
|
||||
final parsed = await Isolate.run(() => parseTranscriptChunk(chunk));
|
||||
// Parse off the UI isolate only when the chunk is big enough to jank a
|
||||
// frame — the initial tail read (up to [_initialTailBytes]) is the case
|
||||
// that froze the app. Streaming appends are small (a message at a time);
|
||||
// parsing those inline avoids spawning a one-shot isolate every poll
|
||||
// tick, which is pure overhead and adds latency under load.
|
||||
final parsed = chunk.length >= _isolateParseThreshold ? await Isolate.run(() => parseTranscriptChunk(chunk)) : parseTranscriptChunk(chunk);
|
||||
if (controller.isClosed) return;
|
||||
for (final w in parsed.warnings) {
|
||||
_onWarn(w);
|
||||
|
||||
Reference in New Issue
Block a user