fix(driver-sql): give the bounded connection attempt an accurate error message (#3769) - #3791
Merged
Merged
Conversation
…r message (#3769) #3781 bounded a connection attempt at 10s via pool.createTimeoutMillis, which stopped the 30s hang but kept knex's own wording: "Timeout acquiring a connection. The pool is probably full". The pool is not full — the server never completed the handshake — so that message sends an operator to tune pool.max while the network is what is broken. Same defect class as #3741's boot guard: an error that reads nothing like its cause. SqlDriver now also sets the DIALECT'S OWN connect timeout, which fails with a message that names what happened: pg / postgres / postgresql / cockroachdb → connectionTimeoutMillis → "timeout expired" mysql / mysql2 → connectTimeout → "connect ETIMEDOUT" Carrying the timeout requires `connection` to be an object, so a URL string moves into the dialect's URL slot (connectionString for pg, uri for mysql2). Measured against a black-holing listener: both forms still reach the URL's own host/port and still honour ?sslmode=require. SQLite is untouched — a file open has no handshake to time out. A function-valued connection is left alone: the host is building each connection itself. The two bounds are deliberately UNEQUAL. They race and knex wins a tie, so equal values let the pool timeout fire first and the accurate message is never seen — caught by the black-hole test, which now asserts the wording rather than merely that something threw. The dialect timeout is the effective bound at 10s; the pool timeout is a strictly looser backstop, 10s → 15s, reached only by a dialect with no connect-timeout knob or one that ignores ours. driver.config keeps the shape the author passed — the rewrite applies only to what knex receives. Two existing readers depend on that: serve.ts's startup banner and createDatabase(), which parses the URL to swap in the maintenance database. A test pins it. createDatabase()'s own admin connection now gets the same bound; it is opened during boot against the very server we already suspect is unreachable. Verified: driver-sql 386, cli 673, objectql 1128, runtime 661. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9VBCNvg9Zixrf1A9Rnwdd
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 8 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…— document the two connect-timeout defaults The drift check flagged drivers.mdx: it said SqlDriver 'accepts a Knex.Config object verbatim', which #3791 makes false — two connect-timeout defaults are now injected. Records both, why they are deliberately unequal, and how to override. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9VBCNvg9Zixrf1A9Rnwdd
os-zhuang
marked this pull request as ready for review
July 28, 2026 05:49
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.
Closes #3769。#3781 做完了"限时"那一半,这个 PR 做"说实话"那一半。
问题
#3781 用
pool.createTimeoutMillis把连接尝试限在 10s,消掉了 30 秒卡死,但保留了 knex 自己的措辞:池并没有满 —— 是服务端从未完成握手。这句话会把运维引去调
pool.max,而坏掉的是网络。这跟 #3741 那个启动守卫是同一类缺陷:报出的错误跟真实原因相距很远。改动
SqlDriver现在同时设置该 dialect 自己的连接超时,它失败时说的是实情:pg/postgres/postgresql/cockroachdbconnectionTimeoutMillistimeout expiredmysql/mysql2connectTimeoutconnect ETIMEDOUT携带超时要求
connection是对象,所以 URL 字符串被搬进该 dialect 的 URL 槽(pg 用connectionString,mysql2 用uri)。两种形式都实测过:连接尝试仍然打到 URL 自己的 host/port(用黑洞监听器的 accept 计数验证),?sslmode=require仍被正确解析。SQLite 完全不碰 —— 打开一个文件没有握手可超时。函数式connection(knex 的 per-acquire provider)也不碰:宿主自己在造连接,超时归它管。两个上限故意不相等
这是写严格断言时才发现的:它们会竞争,而 knex 赢平局。两个都设 10s 时,池超时先触发,准确消息永远说不上话 —— 测试如实变红,我才发现。
所以:dialect 超时是有效上限(10s),池超时是严格更宽的兜底(10s → 15s),只有在某 dialect 没有连接超时旋钮(SQLite)或忽略我们设的值时才会走到。
driver.config保持作者传入的形状重写只作用于交给 knex 的那份。两个既有读取方依赖原形状:
serve.ts的启动横幅,以及createDatabase()(解析 URL 换成维护库)。加了测试钉住这个不变量。createDatabase()自己的 admin 连接也补上了同样的上限 —— 它在启动期连的正是那台我们已经怀疑连不上的服务器,不该成为唯一还等 30 秒的地方。验证
sql-driver-connect-bound.test.ts扩到 12 例:pg/mysql2 的 URL 搬迁形状、对象连接补字段不扰动其余、宿主显式值被尊重、sqlite 不注入、函数式 connection 不动、driver.config形状不变,以及黑洞端点用例现在断言措辞(toContain('timeout expired')+not.toContain('pool is probably full'))而不只是"抛了错"。pnpm build71/71 全绿。顺带发现的既存 bug(未在本 PR 修)
启动横幅的 driver 行显示
Driver: SqlDriver(pg) → (unknown),URL 丢了。我一开始以为是自己引入的,在干净 main 上复现后确认是既存问题:describeRegisteredDriver读到了cfg.client(所以标签对)却没读到 URL。与本次改动无关,按 PD #10 记在这里而不是夹带修复。Generated by Claude Code