Repository navigation
fix(cubejs): stop a cut-off Hasura response from freezing the refresh scheduler - #93
Merged
Merged
Conversation
… scheduler
fetchGraphQL used node-fetch 2, which pipes the response body through a
PassThrough and Gunzip with pipe(). pipe() does not forward an aborted
response, so a gzip + Content-Length body cut off mid-transfer left
res.json() pending forever, and the whole await chain was garbage-collected.
The refresh scheduler fetches its datasource contexts through fetchGraphQL at
the start of every interval and runs contexts serially, so one such hang on
dev (2026-10-08 03:41 UTC) froze pre-aggregation refresh for every tenant for
4.5 days with no error or restart.
Node's built-in fetch rejects ("terminated") on a cut-off body and bounds
headers and body at 300s by default. The regression test serves half a gzip
response and drops the connection; it stayed pending before this change.
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.
Problem
On dev the refresh worker froze on 2026-10-08 03:41 UTC and stopped refreshing pre-aggregations for every tenant for 4.5 days. There were no errors and no restarts. It was reported as abler's BigQuery pre-aggs not updating.
Root cause
At the start of every interval the scheduler fetches its contexts with
fetchGraphQL→getDataSources(), and it runs contexts serially.fetchGraphQLused node-fetch 2.7.0, which pipes the body throughPassThrough→Gunzipwithpipe().pipe()does not forward an aborted response. So when Hasura's gzip + Content-Length response was cut off mid-body,res.json()stayed pending forever. The whole await chain was then garbage-collected and the interval never finished.Evidence from the live process (inspector + heap snapshot):
executionpromise had no async frame retaining itFix
Use Node's built-in
fetch(undici) infetchGraphQL. It rejects withterminatedon a cut-off body and bounds headers and body at 300s by default.eventEmitter.jsstill uses node-fetch, but it is fire-and-forget and not on the scheduler path.Test
src/utils/__tests__/graphql.test.jsserves half of a gzip response and then drops the connection. It stayedpendingbefore this change and isrejectedafter. The full cubejs suite passes 701/703. The 2 failures are the existingruntimeDependencyHardeningchecks of locally installed packages (Docker postinstall only).Dev was unblocked by restarting
synmetrix-cubejs-refresh-worker. A stall monitor follows separately.🤖 Generated with Claude Code