cluster.js
2.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* createDbCluster —— 多连接装配 + 降级 + destroy 去重。
*
* 一期单连接够用:replica / analytics 未注入时降级到 primary(**同一引用**,可用
* `===` 断言),调用方读写分离 / 分析分流的写法不变,二期换真副本零改动。
* 本文件只做装配与降级,不碰任何具体表,不读 env。
*/
import { createDb } from './create-db.js'
import { DbConfigError } from './errors.js'
/**
* @typedef {Object} DbCluster
* @property {import('knex').Knex} primary 主库(读写)
* @property {import('knex').Knex} replica 只读副本(一期 === primary)
* @property {import('knex').Knex} analytics 分析库(一期 === primary)
* @property {() => Promise<void>} destroy 关闭所有去重后的底层连接
*/
/**
* 构造多连接集群。一期 replica/analytics 可省略,省略则降级到 primary(同一引用)。
* @param {Object} cfg
* @param {{url:string,pool?:Object,client?:'mysql2'}} cfg.primary 主库(读写)
* @param {{url:string,pool?:Object,client?:'mysql2'}} [cfg.replica] 只读副本
* @param {{url:string,pool?:Object,client?:'mysql2'}} [cfg.analytics] 分析库
* @returns {DbCluster}
* @throws {DbConfigError} primary 缺失时立即抛
*/
export function createDbCluster(cfg) {
if (!cfg || typeof cfg !== 'object' || !cfg.primary) {
throw new DbConfigError('createDbCluster: cfg.primary is required')
}
const primary = createDb(cfg.primary)
// 降级:未注入副本/分析库 → 显式指向 primary 同一引用(不新建第二个连同库的句柄,
// 避免连接数翻倍)。二期注入真副本/分析库时各自独立。
const replica = cfg.replica ? createDb(cfg.replica) : primary
const analytics = cfg.analytics ? createDb(cfg.analytics) : primary
/**
* 关闭所有去重后的底层连接。同一引用只 destroy 一次,绝不 double-close。
* @returns {Promise<void>}
*/
async function destroy() {
const seen = new Set()
const tasks = []
for (const handle of [primary, replica, analytics]) {
if (seen.has(handle)) continue
seen.add(handle)
tasks.push(handle.destroy())
}
await Promise.all(tasks)
}
return { primary, replica, analytics, destroy }
}