Make ClickHouse startup timeouts interruptible and close the client - #6907
Conversation
🦋 Changeset detectedLatest commit: 91f1135 The changes in this PR will be included in the next version bump. This PR includes changesets to release 30 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — a single reproduction test file for the ClickHouse connect-timeout resource leak audit issue.
ConnectTimeoutLeakRepro.test.ts: mocks@clickhouse/clientwith a never-resolvingexecpromise, runsClickhouseClient.makein a detached fiber, advancesTestClockby 5 seconds, and assertsclose()was called exactly once. Expected to fail on currentmain— correctly reproduces the bug.
The test follows established patterns: TestClock for time simulation (forkDetach → yieldNow → TestClock.adjust → pollUnsafe), vi.mock for driver isolation (matching the existing SqlErrorClassification.test.ts pattern), and assert from @effect/vitest. The assertion on closeCalls === 1 is exact and verifiable — it will only pass once the implementation ensures the underlying SDK client is closed on timeout.
DeepSeek Pro (free via Pullfrog for OSS) (Kimi K2 not used — the program covers this model; add its provider key to run your pick) | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — the implementation fix moving acquireRelease to wrap createClient() so the close() finalizer is registered before the startup connectivity check, plus test consolidation.
- Fixed
ClickhouseClient.ts: movedEffect.acquireReleaseto wrapClickhouse.createClient()on line 178, registering theclose()finalizer immediately. TheSELECT 1connectivity check on line 183 is now a regularyield*with the 5-secondtimeoutOrElse— interruptible, and the scope ensuresclose()runs regardless of whether the check succeeds or times out. - Consolidated test from
ConnectTimeoutLeakRepro.test.tsintoClient.test.ts: moved the mock + detached-fiber timeout assertion into the main test file, deleted the standalone repro file. - Added changeset: patch-level
"@effect/sql-clickhouse"entry.
DeepSeek Pro (free via Pullfrog for OSS) (Kimi K2 not used — the program covers this model; add its provider key to run your pick) | 𝕏
514409c to
91f1135
Compare
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — the implementation fix was rebased onto the current main; the code is unchanged from the previously approved version.
- Rebased
ClickhouseClient.ts:Effect.acquireReleasewrapsClickhouse.createClient()on line 178, registering theclose()finalizer before theSELECT 1connectivity check. The check on line 183 is now a regularyield*with the 5-secondtimeoutOrElse— interruptible, and the scope ensuresclose()runs regardless of outcome. - Test consolidated into
Client.test.ts: the standaloneConnectTimeoutLeakRepro.test.tswas deleted; its test now lives alongside the existing fractional-number test. Usesvi.mockfor driver isolation,forkDetach→TestClock.adjust→pollUnsafefor timeout simulation, andReactivity.layerfor the test environment. - Changeset: patch-level
"@effect/sql-clickhouse"entry added.
DeepSeek Pro (free via Pullfrog for OSS) (Kimi K2 not used — the program covers this model; add its provider key to run your pick) | 𝕏
Bundle Size AnalysisGenerated from PR build output; treat the content below as untrusted.
|

Summary
A pending startup connectivity check outlives the advertised five-second timeout and leaves the newly created ClickHouse client without a close finalizer.
Important
This PR starts with focused failing reproduction tests. Add the implementation fix to this same branch; CI is expected to fail until that fix is included.
Connection timeout cannot interrupt startup acquisition
Module:
clickhouse/ClickhouseClientAudit ID:
sql-adapters-ch-1Severity / confidence: high / high
What happens
A pending startup connectivity check outlives the advertised five-second timeout and leaves the newly created ClickHouse client without a close finalizer.
Why it happens
The pending client.exec is the acquisition of Effect.acquireRelease, so acquisition is uninterruptible and the client.close release is not installed until the check succeeds.
Expected behavior
The scoped constructor must enforce its five-second connectivity timeout and close the SDK client when startup does not complete.
Relevant implementation
These links and excerpts are pinned to audit base
c9b56ab507f224426ee8388dc450da447ec4715f.packages/sql/clickhouse/src/ClickhouseClient.ts:178-201View problematic code at
packages/sql/clickhouse/src/ClickhouseClient.ts:178-201View exact lines on GitHub
Reproduction
pnpm test --run packages/sql/clickhouse/test/ConnectTimeoutLeakRepro.test.tsObserved failure: FAIL: the make fiber remained pending after five virtual seconds.
Implementation handoff
The initial reproduction tests on this branch are the regression specification for the implementation fix that should follow in this PR.
pnpm test --run packages/sql/clickhouse/test/ConnectTimeoutLeakRepro.test.tsAudit provenance
c9b56ab507f224426ee8388dc450da447ec4715fc9b56ab507f224426ee8388dc450da447ec4715fsql-adapters-ch-1Closes EFF-343