一句话说明
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.datasource bindings never resolved to default(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,而不是只改代码。
关联
一句话说明
DatasourceConnectionService.handleFailure()只在「external +validation.onMismatch: 'fail'」时 fail-fast,其余一律降级成 warning。但被object.datasource === name显式绑定的 datasource 连不上,等于那批对象全部不可用 —— 而这些对象不会回落到defaultdriver,它们在查询时直接抛。于是又是一次"启动静默通过、请求时才炸"。#3741 / #3751 刚在
ObjectQLEngine.init()那一层把同样的形状修掉了。这一层的边界还画在旧位置。事实核实
packages/services/service-datasource/src/datasource-connection-service.ts:330-349:配合同文件的 D2 gate(
isDatasourceAddressed,:140-168),boot 期会自动连接三类 datasource:schemaMode !== 'managed')onMismatch: 'fail'→ 抛;否则 warningdatasource: '<name>'绑定它autoConnect: true问题在 (b)。同文件 :151-159 自己的注释写明了后果:
也就是说:显式绑定到某个 datasource 的对象,在该 datasource 没连上时没有任何回落路径 —— 每一次针对它们的查询都会抛"driver 未注册"。启动时只留下一条 warning。
影响
一个 app 声明
datasource: 'analytics'并把 20 个对象绑上去,ANALYTICS_URL配错或那台库没起来:这跟 #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 名。关联
ObjectQLEngine.init()层的同一形状,已按方案 A 修)