Repository navigation
显式绑定的 datasource 连不上只降级成一条 warning:绑上去的对象在启动后全废,直到查询时才炸 #3758
Description
一句话说明
DatasourceConnectionService.handleFailure() 只在「external + validation.onMismatch: 'fail'」时 fail-fast,其余一律降级成 warning。但被 object.datasource === name 显式绑定的 datasource 连不上,等于那批对象全部不可用 —— 而这些对象不会回落到 default driver,它们在查询时直接抛。于是又是一次"启动静默通过、请求时才炸"。
#3741 / #3751 刚在 ObjectQLEngine.init() 那一层把同样的形状修掉了。这一层的边界还画在旧位置。
事实核实
packages/services/service-datasource/src/datasource-connection-service.ts:330-349:
private handleFailure(
record: ConnectableDatasource,
status: ConnectStatus,
reason: string,
context?: DatasourceConnectContext,
): ConnectResult {
const isExternal = record.schemaMode && record.schemaMode !== 'managed';
const failFast =
context?.trigger === 'declared-auto' &&
isExternal &&
record.external?.validation?.onMismatch === 'fail';
const msg = `datasource '${record.name}': connect failed — ${reason}`;
if (failFast) {
throw new Error(
`${msg}. (schemaMode=${record.schemaMode}, validation.onMismatch='fail' ⇒ fail-fast per ADR-0062 D5)`,
);
}
this.logger?.warn?.(`${msg} — degrading (datasource left unconnected)`);
return { name: record.name, status, reason };
}配合同文件的 D2 gate(isDatasourceAddressed,:140-168),boot 期会自动连接三类 datasource:
| 条件 | 连不上时 | |
|---|---|---|
| (a) | external(schemaMode !== 'managed') |
onMismatch: 'fail' → 抛;否则 warning |
| (b) | 有对象显式 datasource: '<name>' 绑定它 |
一律 warning |
| (c) | autoConnect: true |
一律 warning |
问题在 (b)。同文件 :151-159 自己的注释写明了后果:
External datasources and explicit
object.datasourcebindings never resolved todefault(they throw when unregistered)
也就是说:显式绑定到某个 datasource 的对象,在该 datasource 没连上时没有任何回落路径 —— 每一次针对它们的查询都会抛"driver 未注册"。启动时只留下一条 warning。
影响
一个 app 声明 datasource: 'analytics' 并把 20 个对象绑上去,ANALYTICS_URL 配错或那台库没起来:
- 服务器正常启动,没有任何非零退出、没有任何显式信号。
- 那 20 个对象的所有读写全部失败,报的是"driver 未注册"这种跟真实原因(连不上 analytics 库)相距很远的错。
- 剩下的对象工作正常,所以整体看起来"服务是好的",只是"某些页面坏了" —— 比整体宕机更难定位。
这跟 #3741 修掉的是同一个决定,只是发生在另一个 datasource 注册路径上。#3751 让 boot 期主 driver 连不上就拒绝启动,而这里一个被 20 个对象依赖的 datasource 连不上,只值一条 warning。
建议处置
"boot 期主库 vs runtime 加的可选副本"的区分是对的,但 (b) 落错了边。 显式 object.datasource 绑定表达的是一个硬依赖 —— 作者已经明说了这些对象只能从这里读 —— 它跟主库失联没有本质区别。
倾向:把 (b) 提升为 fail-fast,与 (a)+onMismatch:'fail' 并列,理由是它同样没有回落路径。(c) autoConnect: true 保持宽容(那是"能连就连"的语义,没有对象声明依赖它)。
需要一并决定的:
- 逃生阀是否共用
OS_ALLOW_DRIVER_CONNECT_FAILURE。 倾向共用 —— 操作者的意图是同一个("我知道数据库连不上,照样起"),两个旗标只会让人漏设一个。 isDatasourceAddressed里 (b) 的判定发生在connect()之前,绑定对象列表已经算好并传进connect(ds, { objects: bound }),所以handleFailure拿得到"有几个对象依赖它" —— 错误消息里应该直接列出来,而不是只给 datasource 名。- 现有行为是 ADR-0062 D5 明文写下的,改动需要同步更新 ADR,而不是只改代码。
关联
- ObjectQLEngine.init() 吞掉 driver 连接失败:连不上数据库的服务器照常启动,driver 的启动期致命错误被降级成运行时报错 #3741 / feat(objectql)!: refuse to boot when a data driver fails to connect (#3741) #3751(
ObjectQLEngine.init()层的同一形状,已按方案 A 修) - ADR-0062 D5(当前 failure policy 的出处)
- Prime Directive chore: version packages #10
Activity
fix(datasource): an explicitly-bound datasource that cannot connect r…