fix(oracle): a failed connect closes the pool it created (#1102) - #1105
Merged
Merged
Conversation
`createPool` resolves before anything is dialled in Thin mode, so a connect that failed on its test borrow left a live pool behind with no reference to it. `factory.getOrCreateProvider()` never caches a provider whose `connect()` threw, so no later `disconnect()` could reach that pool, and node-oracledb's background creator keeps reaching for `poolMin` connections with no delay between attempts: ~14,000 TCP connects and one full CPU core per second, forever. The catch now closes the pool with `close(0)` and clears `this.pool` before rethrowing, which also fixes the silent retry - left set, the `if (this.pool)` guard returned without dialling and without an error. A close that rejects is swallowed rather than replacing the connect error. Same contract PostgreSQL and SQL Server already follow. docs/providers/oracle.md gains the reason and the measured numbers, per the provider triad.
sloemo01
force-pushed
the
fix/1102-oracle-pool-orphan
branch
from
September 23, 2026 22:44
b1c6d21 to
81bf137
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Inserting the new §3.6 moved Privilege-resilient monitoring to §3.7; the reference at line 1587 still named the old anchor, which no longer exists.
Contributor
Author
|
Fixed in You are right, and it was a miss on my side: inserting the new section made the monitoring one One line, at Checked the rest of the file while I was in there: every other internal anchor resolves against a real heading, and there are no remaining |
cevheri
approved these changes
Sep 24, 2026
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.
Resolves #1102.
What this is
OracleProvider.connect()built its pool, then tested it with a borrow. When that borrow failed, thecatchrethrew without closing the pool and without clearingthis.pool.factory.getOrCreateProvider()never caches a provider whoseconnect()threw, so nothing held a reference that could close it, and node-oracledb's background creator keeps reaching forpoolMinconnections with no delay between attempts — a spinning core and a connection flood that outlives the process's usefulness.The
catchnow does what PostgreSQL and SQL Server already do:close(0)is the oracledb equivalent ofend(). Clearingthis.poolmatters as much as closing: left set, theif (this.pool)guard at the top ofconnect()returns on a retry without dialling and without an error, so a caller that retries reads a silent success. The ticket lists this as a second, smaller defect from the same line, and one test arm covers it directly.A
close()that itself rejects is swallowed, so a cleanup failure never becomes the reason a connect was refused.Tests, written first
Four arms in
tests/integration/db/oracle-provider.test.ts, using the file's existingmockCreatePoolFn/mockPoolCloseFndoubles:getConnectionfailure closes the pool it just createdclosecalled 0 timesclosecalled 0 timesconnect()returned earlyclosenever attemptedAll four failed on current
main(209 pass, 4 fail), all four pass with the fix (213 pass). The arms countclosecalls rather than asserting onthis.poolalone, because a pool can be unreferenced and still running — which is the defect, and the reason anullcheck would have gone green on the broken code.Two of the arms pin things the acceptance criteria ask for explicitly: the NJS-138 path (
mapped instanceof DatabaseConfigErrorthrows before the fix's code would have run in a naive ordering) and the error-identity rule that a rejectedclosemust not replace the original connect error.Docs
docs/providers/oracle.mdgains §3.6, recording why a failed connect closes its own pool and the measured cost of not doing it, per the provider triad rule inCLAUDE.md.Verification
bun tests/run-tests.ts tests/integration/db/oracle-provider.test.ts—213 pass, and 100% line coverage onsrc/lib/db/providers/sql/oracle.ts(1012/1012, zero uncovered lines) from the lcov this PR produces.bun run formatclean,bun run lint0 errors,bun run typecheckclean.One thing worth stating plainly rather than burying: the repo's full suite does not go green in this environment, and not because of this change. On a clean
origin/mainwith this branch absent, these files already fail:sqlite-provider(83),sqlite-driver(27),launcher-utils(6),object-edit-declarations(4),result-pagination-capability(4),object-source-declarations(3),object-column-declarations(3),agent-investigation-e2e(2),test-runner-cli(2),monaco-language-ids(1),agent-statement-boundary(1), andmongodb-providerexits without writing a report. The identical list appears with my change applied. Since those abortbun run test:coveragebefore the lcov merge, I verified the coverage gate for the file this PR touches instead of claiming the global gate passed.