monsqlize 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -60
- package/LICENSE +201 -21
- package/README.md +537 -1828
- package/changelogs/README.md +160 -0
- package/changelogs/v2.0.0.md +222 -0
- package/dist/cjs/index.cjs +10600 -0
- package/dist/cjs/mongodb/common/transaction-aware.cjs +10 -0
- package/dist/cjs/transaction/CacheLockManager.cjs +100 -0
- package/dist/cjs/transaction/Transaction.cjs +158 -0
- package/dist/cjs/transaction/TransactionManager.cjs +298 -0
- package/dist/esm/index.mjs +10650 -0
- package/dist/types/base.d.ts +81 -0
- package/dist/types/collection.d.ts +1031 -0
- package/dist/types/expression.d.ts +115 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/lock.d.ts +74 -0
- package/dist/types/model.d.ts +526 -0
- package/dist/types/mongodb.d.ts +49 -0
- package/dist/types/monsqlize.d.ts +491 -0
- package/dist/types/pool.d.ts +84 -0
- package/dist/types/runtime.d.ts +362 -0
- package/dist/types/saga.d.ts +143 -0
- package/dist/types/slow-query-log.d.ts +126 -0
- package/dist/types/sync.d.ts +103 -0
- package/dist/types/transaction.d.ts +132 -0
- package/package.json +67 -69
- package/index.d.ts +0 -206
- package/index.mjs +0 -52
- package/lib/cache-invalidation.js +0 -279
- package/lib/cache.js +0 -530
- package/lib/common/cursor.js +0 -59
- package/lib/common/docs-urls.js +0 -73
- package/lib/common/index-options.js +0 -223
- package/lib/common/log.js +0 -61
- package/lib/common/namespace.js +0 -22
- package/lib/common/normalize.js +0 -34
- package/lib/common/page-result.js +0 -43
- package/lib/common/runner.js +0 -57
- package/lib/common/server-features.js +0 -232
- package/lib/common/shape-builders.js +0 -27
- package/lib/common/validation.js +0 -113
- package/lib/connect.js +0 -99
- package/lib/constants.js +0 -55
- package/lib/count-queue.js +0 -188
- package/lib/distributed-cache-invalidator.js +0 -260
- package/lib/errors.js +0 -168
- package/lib/expression/cache/ExpressionCache.js +0 -114
- package/lib/expression/compiler/ExpressionCompiler.js +0 -1090
- package/lib/expression/compiler/ExpressionCompilerExtensions.js +0 -531
- package/lib/expression/detector.js +0 -84
- package/lib/expression/factory.js +0 -29
- package/lib/expression/index.js +0 -19
- package/lib/function-cache.js +0 -533
- package/lib/index.js +0 -1251
- package/lib/infrastructure/ConnectionPoolManager.js +0 -464
- package/lib/infrastructure/HealthChecker.js +0 -281
- package/lib/infrastructure/PoolConfig.js +0 -199
- package/lib/infrastructure/PoolSelector.js +0 -225
- package/lib/infrastructure/PoolStats.js +0 -244
- package/lib/infrastructure/ssh-tunnel-ssh2.js +0 -212
- package/lib/infrastructure/ssh-tunnel.js +0 -41
- package/lib/infrastructure/uri-parser.js +0 -36
- package/lib/lock/Lock.js +0 -67
- package/lib/lock/errors.js +0 -28
- package/lib/lock/index.js +0 -13
- package/lib/logger.js +0 -225
- package/lib/model/examples/test.js +0 -311
- package/lib/model/features/defaults.js +0 -161
- package/lib/model/features/populate.js +0 -568
- package/lib/model/features/relations.js +0 -120
- package/lib/model/features/soft-delete.js +0 -349
- package/lib/model/features/version.js +0 -157
- package/lib/model/features/virtuals.js +0 -219
- package/lib/model/index.js +0 -1265
- package/lib/mongodb/common/accessor-helpers.js +0 -59
- package/lib/mongodb/common/agg-pipeline.js +0 -36
- package/lib/mongodb/common/aggregation-validator.js +0 -127
- package/lib/mongodb/common/iid.js +0 -28
- package/lib/mongodb/common/lexicographic-expr.js +0 -53
- package/lib/mongodb/common/shape.js +0 -32
- package/lib/mongodb/common/sort.js +0 -39
- package/lib/mongodb/common/transaction-aware.js +0 -25
- package/lib/mongodb/connect.js +0 -234
- package/lib/mongodb/index.js +0 -639
- package/lib/mongodb/management/admin-ops.js +0 -200
- package/lib/mongodb/management/bookmark-ops.js +0 -167
- package/lib/mongodb/management/cache-ops.js +0 -50
- package/lib/mongodb/management/collection-ops.js +0 -387
- package/lib/mongodb/management/database-ops.js +0 -202
- package/lib/mongodb/management/index-ops.js +0 -475
- package/lib/mongodb/management/index.js +0 -17
- package/lib/mongodb/management/namespace.js +0 -31
- package/lib/mongodb/management/validation-ops.js +0 -268
- package/lib/mongodb/queries/aggregate.js +0 -172
- package/lib/mongodb/queries/chain.js +0 -631
- package/lib/mongodb/queries/count.js +0 -99
- package/lib/mongodb/queries/distinct.js +0 -78
- package/lib/mongodb/queries/find-and-count.js +0 -193
- package/lib/mongodb/queries/find-by-ids.js +0 -236
- package/lib/mongodb/queries/find-one-by-id.js +0 -171
- package/lib/mongodb/queries/find-one.js +0 -71
- package/lib/mongodb/queries/find-page.js +0 -618
- package/lib/mongodb/queries/find.js +0 -171
- package/lib/mongodb/queries/index.js +0 -51
- package/lib/mongodb/queries/watch.js +0 -538
- package/lib/mongodb/writes/common/batch-retry.js +0 -65
- package/lib/mongodb/writes/delete-batch.js +0 -323
- package/lib/mongodb/writes/delete-many.js +0 -181
- package/lib/mongodb/writes/delete-one.js +0 -173
- package/lib/mongodb/writes/find-one-and-delete.js +0 -203
- package/lib/mongodb/writes/find-one-and-replace.js +0 -239
- package/lib/mongodb/writes/find-one-and-update.js +0 -240
- package/lib/mongodb/writes/increment-one.js +0 -259
- package/lib/mongodb/writes/index.js +0 -46
- package/lib/mongodb/writes/insert-batch.js +0 -508
- package/lib/mongodb/writes/insert-many.js +0 -223
- package/lib/mongodb/writes/insert-one.js +0 -169
- package/lib/mongodb/writes/replace-one.js +0 -226
- package/lib/mongodb/writes/result-handler.js +0 -237
- package/lib/mongodb/writes/update-batch.js +0 -416
- package/lib/mongodb/writes/update-many.js +0 -275
- package/lib/mongodb/writes/update-one.js +0 -273
- package/lib/mongodb/writes/upsert-one.js +0 -203
- package/lib/multi-level-cache.js +0 -244
- package/lib/operators.js +0 -330
- package/lib/redis-cache-adapter.js +0 -267
- package/lib/saga/SagaContext.js +0 -67
- package/lib/saga/SagaDefinition.js +0 -32
- package/lib/saga/SagaExecutor.js +0 -201
- package/lib/saga/SagaOrchestrator.js +0 -186
- package/lib/saga/index.js +0 -11
- package/lib/slow-query-log/base-storage.js +0 -70
- package/lib/slow-query-log/batch-queue.js +0 -97
- package/lib/slow-query-log/config-manager.js +0 -196
- package/lib/slow-query-log/index.js +0 -238
- package/lib/slow-query-log/mongodb-storage.js +0 -324
- package/lib/slow-query-log/query-hash.js +0 -39
- package/lib/sync/ChangeStreamSyncManager.js +0 -405
- package/lib/sync/ResumeTokenStore.js +0 -192
- package/lib/sync/SyncConfig.js +0 -127
- package/lib/sync/SyncTarget.js +0 -240
- package/lib/sync/index.js +0 -20
- package/lib/transaction/CacheLockManager.js +0 -162
- package/lib/transaction/DistributedCacheLockManager.js +0 -475
- package/lib/transaction/Transaction.js +0 -315
- package/lib/transaction/TransactionManager.js +0 -267
- package/lib/transaction/index.js +0 -11
- package/lib/utils/objectid-converter.js +0 -632
- package/types/README.md +0 -122
- package/types/base.ts +0 -94
- package/types/batch.ts +0 -187
- package/types/cache.ts +0 -71
- package/types/chain.ts +0 -254
- package/types/collection.ts +0 -357
- package/types/expression.ts +0 -109
- package/types/function-cache.d.ts +0 -135
- package/types/lock.ts +0 -95
- package/types/model/definition.ts +0 -152
- package/types/model/index.ts +0 -10
- package/types/model/instance.ts +0 -121
- package/types/model/relations.ts +0 -121
- package/types/model/virtuals.ts +0 -32
- package/types/monsqlize.ts +0 -245
- package/types/options.ts +0 -192
- package/types/pagination.ts +0 -154
- package/types/pool.ts +0 -125
- package/types/query.ts +0 -71
- package/types/saga.ts +0 -125
- package/types/stream.ts +0 -64
- package/types/sync.ts +0 -79
- package/types/transaction.ts +0 -79
- package/types/write.ts +0 -77
package/lib/saga/SagaExecutor.js
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Saga 执行器
|
|
3
|
-
* 负责步骤执行和补偿
|
|
4
|
-
*/
|
|
5
|
-
const SagaContext = require('./SagaContext');
|
|
6
|
-
|
|
7
|
-
class SagaExecutor {
|
|
8
|
-
/**
|
|
9
|
-
* 构造函数
|
|
10
|
-
* @param {Object} definition - Saga 定义
|
|
11
|
-
* @param {Object} data - 执行数据
|
|
12
|
-
* @param {Object} orchestrator - Saga 协调器
|
|
13
|
-
*/
|
|
14
|
-
constructor(definition, data, orchestrator) {
|
|
15
|
-
this.definition = definition;
|
|
16
|
-
this.orchestrator = orchestrator;
|
|
17
|
-
this.context = new SagaContext(this._generateSagaId(), data);
|
|
18
|
-
this.completedSteps = [];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 执行 Saga
|
|
23
|
-
* @returns {Promise<Object>} 执行结果
|
|
24
|
-
*/
|
|
25
|
-
async execute() {
|
|
26
|
-
const startTime = Date.now();
|
|
27
|
-
|
|
28
|
-
this.orchestrator.logger?.info(
|
|
29
|
-
`[Saga] 开始执行: ${this.definition.name} (${this.context.sagaId})`
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
// 顺序执行步骤
|
|
34
|
-
for (let i = 0; i < this.definition.steps.length; i++) {
|
|
35
|
-
const step = this.definition.steps[i];
|
|
36
|
-
|
|
37
|
-
this.orchestrator.logger?.info(
|
|
38
|
-
`[Saga] 执行步骤 ${i + 1}/${this.definition.steps.length}: ${step.name}`
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
const stepStartTime = Date.now();
|
|
42
|
-
|
|
43
|
-
// 执行步骤
|
|
44
|
-
const result = await step.execute(this.context);
|
|
45
|
-
|
|
46
|
-
const stepDuration = Date.now() - stepStartTime;
|
|
47
|
-
|
|
48
|
-
// 记录成功的步骤
|
|
49
|
-
this.completedSteps.push({
|
|
50
|
-
step,
|
|
51
|
-
index: i,
|
|
52
|
-
result,
|
|
53
|
-
duration: stepDuration,
|
|
54
|
-
timestamp: Date.now()
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// 标记步骤完成
|
|
58
|
-
this.context.markStepCompleted(step.name, result);
|
|
59
|
-
|
|
60
|
-
this.orchestrator.logger?.info(
|
|
61
|
-
`[Saga] 步骤完成: ${step.name} (耗时 ${stepDuration}ms)`
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const totalDuration = Date.now() - startTime;
|
|
66
|
-
|
|
67
|
-
this.orchestrator.logger?.info(
|
|
68
|
-
`[Saga] 执行成功: ${this.definition.name} (总耗时 ${totalDuration}ms)`
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
success: true,
|
|
73
|
-
sagaId: this.context.sagaId,
|
|
74
|
-
sagaName: this.definition.name,
|
|
75
|
-
completedSteps: this.completedSteps.length,
|
|
76
|
-
duration: totalDuration
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
} catch (error) {
|
|
80
|
-
const totalDuration = Date.now() - startTime;
|
|
81
|
-
|
|
82
|
-
this.orchestrator.logger?.error(
|
|
83
|
-
`[Saga] 执行失败: ${this.definition.name}, 错误: ${error.message}`
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
// 自动补偿
|
|
87
|
-
const compensationResult = await this._compensate(error);
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
success: false,
|
|
91
|
-
sagaId: this.context.sagaId,
|
|
92
|
-
sagaName: this.definition.name,
|
|
93
|
-
completedSteps: this.completedSteps.length,
|
|
94
|
-
failedStep: this.completedSteps.length,
|
|
95
|
-
error: error.message,
|
|
96
|
-
duration: totalDuration,
|
|
97
|
-
compensation: compensationResult
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 补偿已完成的步骤
|
|
104
|
-
* @private
|
|
105
|
-
* @param {Error} originalError - 原始错误
|
|
106
|
-
* @returns {Promise<Object>} 补偿结果
|
|
107
|
-
*/
|
|
108
|
-
async _compensate(originalError) {
|
|
109
|
-
this.orchestrator.logger?.warn(
|
|
110
|
-
`[Saga] 开始补偿: ${this.completedSteps.length} 个已完成步骤`
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
const compensationResults = [];
|
|
114
|
-
|
|
115
|
-
// 逆序补偿
|
|
116
|
-
for (let i = this.completedSteps.length - 1; i >= 0; i--) {
|
|
117
|
-
const completed = this.completedSteps[i];
|
|
118
|
-
const step = completed.step;
|
|
119
|
-
|
|
120
|
-
if (!step.compensate) {
|
|
121
|
-
this.orchestrator.logger?.warn(
|
|
122
|
-
`[Saga] 步骤 ${step.name} 没有定义补偿操作,跳过`
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
compensationResults.push({
|
|
126
|
-
stepName: step.name,
|
|
127
|
-
success: false,
|
|
128
|
-
reason: 'no-compensate-defined'
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
this.orchestrator.logger?.info(
|
|
136
|
-
`[Saga] 补偿步骤: ${step.name}`
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
const startTime = Date.now();
|
|
140
|
-
|
|
141
|
-
await step.compensate(this.context, completed.result);
|
|
142
|
-
|
|
143
|
-
const duration = Date.now() - startTime;
|
|
144
|
-
|
|
145
|
-
this.orchestrator.logger?.info(
|
|
146
|
-
`[Saga] 补偿成功: ${step.name} (耗时 ${duration}ms)`
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
compensationResults.push({
|
|
150
|
-
stepName: step.name,
|
|
151
|
-
success: true,
|
|
152
|
-
duration
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
} catch (compensateError) {
|
|
156
|
-
this.orchestrator.logger?.error(
|
|
157
|
-
`[Saga] 补偿失败: ${step.name}, 错误: ${compensateError.message}`
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
compensationResults.push({
|
|
161
|
-
stepName: step.name,
|
|
162
|
-
success: false,
|
|
163
|
-
error: compensateError.message
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// 检查是否所有补偿都成功
|
|
169
|
-
const allSuccess = compensationResults.every(
|
|
170
|
-
r => r.success || r.reason === 'no-compensate-defined'
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
if (!allSuccess) {
|
|
174
|
-
this.orchestrator.logger?.error(
|
|
175
|
-
'[Saga] 部分补偿失败,需要人工介入'
|
|
176
|
-
);
|
|
177
|
-
} else {
|
|
178
|
-
this.orchestrator.logger?.info(
|
|
179
|
-
'[Saga] 所有补偿完成'
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
success: allSuccess,
|
|
185
|
-
results: compensationResults
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* 生成 Saga ID
|
|
191
|
-
* @private
|
|
192
|
-
* @returns {string} Saga ID
|
|
193
|
-
*/
|
|
194
|
-
_generateSagaId() {
|
|
195
|
-
return `saga_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
module.exports = SagaExecutor;
|
|
200
|
-
|
|
201
|
-
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Saga 协调器
|
|
3
|
-
* 负责管理所有 Saga 定义
|
|
4
|
-
* 支持 Redis 存储(多进程共享)或内存存储(单进程)
|
|
5
|
-
*/
|
|
6
|
-
const SagaDefinition = require('./SagaDefinition');
|
|
7
|
-
|
|
8
|
-
class SagaOrchestrator {
|
|
9
|
-
/**
|
|
10
|
-
* 构造函数
|
|
11
|
-
* @param {Object} options - 配置选项
|
|
12
|
-
* @param {Object} [options.cache] - 缓存实例(可选,Redis 或内存)
|
|
13
|
-
* @param {Object} [options.logger] - 日志记录器(可选)
|
|
14
|
-
*/
|
|
15
|
-
constructor(options = {}) {
|
|
16
|
-
this.cache = options.cache;
|
|
17
|
-
this.logger = options.logger;
|
|
18
|
-
|
|
19
|
-
// 存储策略:根据 cache 配置自动选择
|
|
20
|
-
// 只有当 cache 存在且是 Redis 实例时才使用 Redis 存储
|
|
21
|
-
if (this.cache && this.cache !== false && typeof this.cache.set === 'function') {
|
|
22
|
-
// 检测是否为 Redis(通过检查特定方法)
|
|
23
|
-
const isRedis = typeof this.cache.keys === 'function' &&
|
|
24
|
-
typeof this.cache.publish === 'function';
|
|
25
|
-
|
|
26
|
-
if (isRedis) {
|
|
27
|
-
// Redis 模式:使用 cache.set/get 存储 Saga 元数据
|
|
28
|
-
this.useRedis = true;
|
|
29
|
-
this.sagaKeyPrefix = 'monsqlize:saga:def:';
|
|
30
|
-
this.logger?.debug('[Saga] 使用 Redis 存储(多进程共享)');
|
|
31
|
-
} else {
|
|
32
|
-
// 内存缓存模式:使用 Map 存储
|
|
33
|
-
this.sagas = new Map();
|
|
34
|
-
this.useRedis = false;
|
|
35
|
-
this.logger?.debug('[Saga] 使用内存缓存(单进程,Saga 元数据不共享)');
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
// 内存模式:使用 Map 存储
|
|
39
|
-
this.sagas = new Map();
|
|
40
|
-
this.useRedis = false;
|
|
41
|
-
this.logger?.debug('[Saga] 使用内存存储(单进程)');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 统计信息
|
|
45
|
-
this.stats = {
|
|
46
|
-
totalExecutions: 0,
|
|
47
|
-
successfulExecutions: 0,
|
|
48
|
-
failedExecutions: 0,
|
|
49
|
-
compensatedExecutions: 0
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 定义 Saga
|
|
55
|
-
* @param {Object} config - Saga 配置
|
|
56
|
-
* @param {string} config.name - Saga 名称
|
|
57
|
-
* @param {Array} config.steps - Saga 步骤列表
|
|
58
|
-
* @returns {SagaDefinition} Saga 定义实例
|
|
59
|
-
*/
|
|
60
|
-
async defineSaga(config) {
|
|
61
|
-
this._validateConfig(config);
|
|
62
|
-
|
|
63
|
-
const saga = new SagaDefinition(config, this);
|
|
64
|
-
|
|
65
|
-
if (this.useRedis) {
|
|
66
|
-
// 存储元数据到 Redis
|
|
67
|
-
await this.cache.set(
|
|
68
|
-
this.sagaKeyPrefix + config.name,
|
|
69
|
-
{
|
|
70
|
-
name: config.name,
|
|
71
|
-
steps: config.steps.map(s => ({
|
|
72
|
-
name: s.name,
|
|
73
|
-
hasCompensate: !!s.compensate
|
|
74
|
-
}))
|
|
75
|
-
},
|
|
76
|
-
0 // TTL=0 永久存储
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
// 函数保存在内存
|
|
80
|
-
if (!this.sagas) this.sagas = new Map();
|
|
81
|
-
this.sagas.set(config.name, saga);
|
|
82
|
-
} else {
|
|
83
|
-
this.sagas.set(config.name, saga);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
this.logger?.debug(`[Saga] 定义 Saga: ${config.name}`);
|
|
87
|
-
return saga;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 执行 Saga
|
|
92
|
-
* @param {string} sagaName - Saga 名称
|
|
93
|
-
* @param {Object} data - 执行数据
|
|
94
|
-
* @returns {Promise<Object>} 执行结果
|
|
95
|
-
*/
|
|
96
|
-
async execute(sagaName, data) {
|
|
97
|
-
const saga = this.sagas?.get(sagaName);
|
|
98
|
-
|
|
99
|
-
if (!saga && this.useRedis) {
|
|
100
|
-
// 检查 Redis 中是否存在
|
|
101
|
-
const key = this.sagaKeyPrefix + sagaName;
|
|
102
|
-
const def = await this.cache.get(key);
|
|
103
|
-
|
|
104
|
-
if (def) {
|
|
105
|
-
throw new Error(
|
|
106
|
-
`Saga '${sagaName}' 在 Redis 中存在但未在当前进程注册。` +
|
|
107
|
-
'请在进程启动时调用 defineSaga() 注册。'
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (!saga) {
|
|
113
|
-
throw new Error(`Saga '${sagaName}' 未定义`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
this.stats.totalExecutions++;
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const result = await saga.execute(data);
|
|
120
|
-
|
|
121
|
-
if (result.success) {
|
|
122
|
-
this.stats.successfulExecutions++;
|
|
123
|
-
} else {
|
|
124
|
-
this.stats.failedExecutions++;
|
|
125
|
-
this.stats.compensatedExecutions++;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return result;
|
|
129
|
-
} catch (error) {
|
|
130
|
-
this.stats.failedExecutions++;
|
|
131
|
-
throw error;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* 列出所有已定义的 Saga
|
|
137
|
-
* @returns {Promise<string[]>} Saga 名称列表
|
|
138
|
-
*/
|
|
139
|
-
async listSagas() {
|
|
140
|
-
if (this.useRedis) {
|
|
141
|
-
const keys = await this.cache.keys(this.sagaKeyPrefix + '*');
|
|
142
|
-
return keys.map(key => key.replace(this.sagaKeyPrefix, ''));
|
|
143
|
-
} else {
|
|
144
|
-
return Array.from(this.sagas.keys());
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* 获取统计信息
|
|
150
|
-
* @returns {Object} 统计信息
|
|
151
|
-
*/
|
|
152
|
-
getStats() {
|
|
153
|
-
return {
|
|
154
|
-
...this.stats,
|
|
155
|
-
successRate: this.stats.totalExecutions > 0
|
|
156
|
-
? ((this.stats.successfulExecutions / this.stats.totalExecutions) * 100).toFixed(2) + '%'
|
|
157
|
-
: '0%',
|
|
158
|
-
storageMode: this.useRedis ? 'Redis' : '内存'
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* 验证 Saga 配置
|
|
164
|
-
* @private
|
|
165
|
-
* @param {Object} config - Saga 配置
|
|
166
|
-
*/
|
|
167
|
-
_validateConfig(config) {
|
|
168
|
-
if (!config.name) {
|
|
169
|
-
throw new Error('Saga name is required');
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (!Array.isArray(config.steps) || config.steps.length === 0) {
|
|
173
|
-
throw new Error('Saga steps must be a non-empty array');
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
for (const step of config.steps) {
|
|
177
|
-
if (!step.name || !step.execute) {
|
|
178
|
-
throw new Error('Each step must have name and execute function');
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
module.exports = SagaOrchestrator;
|
|
185
|
-
|
|
186
|
-
|
package/lib/saga/index.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 慢查询日志存储接口
|
|
3
|
-
* 所有存储适配器必须实现此接口
|
|
4
|
-
*
|
|
5
|
-
* @version 1.3.0
|
|
6
|
-
* @since 2025-12-22
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
class ISlowQueryLogStorage {
|
|
10
|
-
/**
|
|
11
|
-
* 初始化存储(创建集合/表、索引等)
|
|
12
|
-
* @returns {Promise<void>}
|
|
13
|
-
*/
|
|
14
|
-
async initialize() {
|
|
15
|
-
throw new Error('ISlowQueryLogStorage.initialize() must be implemented');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 保存单条慢查询日志
|
|
20
|
-
* @param {Object} log - 慢查询日志对象
|
|
21
|
-
* @param {string} log.db - 数据库名
|
|
22
|
-
* @param {string} log.collection - 集合名
|
|
23
|
-
* @param {string} log.operation - 操作类型
|
|
24
|
-
* @param {Object} log.queryShape - 查询模式(已脱敏)
|
|
25
|
-
* @param {number} log.executionTimeMs - 执行时间(毫秒)
|
|
26
|
-
* @param {Date} log.timestamp - 时间戳
|
|
27
|
-
* @param {Object} [log.metadata] - 扩展元数据
|
|
28
|
-
* @returns {Promise<void>}
|
|
29
|
-
*/
|
|
30
|
-
async save(log) {
|
|
31
|
-
throw new Error('ISlowQueryLogStorage.save() must be implemented');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* 批量保存慢查询日志
|
|
36
|
-
* @param {Object[]} logs - 慢查询日志数组
|
|
37
|
-
* @returns {Promise<void>}
|
|
38
|
-
*/
|
|
39
|
-
async saveBatch(logs) {
|
|
40
|
-
throw new Error('ISlowQueryLogStorage.saveBatch() must be implemented');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 查询慢查询日志
|
|
45
|
-
* @param {Object} filter - 查询条件
|
|
46
|
-
* @param {string} [filter.db] - 数据库名
|
|
47
|
-
* @param {string} [filter.collection] - 集合名
|
|
48
|
-
* @param {string} [filter.operation] - 操作类型
|
|
49
|
-
* @param {Object} options - 查询选项
|
|
50
|
-
* @param {Object} [options.sort] - 排序规则
|
|
51
|
-
* @param {number} [options.limit] - 限制数量
|
|
52
|
-
* @param {number} [options.skip] - 跳过数量
|
|
53
|
-
* @returns {Promise<Object[]>}
|
|
54
|
-
*/
|
|
55
|
-
async query(filter, options) {
|
|
56
|
-
throw new Error('ISlowQueryLogStorage.query() must be implemented');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 关闭连接
|
|
61
|
-
* @returns {Promise<void>}
|
|
62
|
-
*/
|
|
63
|
-
async close() {
|
|
64
|
-
throw new Error('ISlowQueryLogStorage.close() must be implemented');
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
module.exports = { ISlowQueryLogStorage };
|
|
69
|
-
|
|
70
|
-
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 批量队列管理器
|
|
3
|
-
* 用于批量写入慢查询日志,优化性能
|
|
4
|
-
*
|
|
5
|
-
* @version 1.3.0
|
|
6
|
-
* @since 2025-12-22
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
class BatchQueue {
|
|
10
|
-
/**
|
|
11
|
-
* 创建批量队列
|
|
12
|
-
* @param {Object} storage - 存储适配器实例
|
|
13
|
-
* @param {Object} options - 队列配置
|
|
14
|
-
* @param {number} [options.batchSize=10] - 批量大小
|
|
15
|
-
* @param {number} [options.flushInterval=5000] - 刷新间隔(毫秒)
|
|
16
|
-
* @param {number} [options.maxBufferSize=100] - 最大缓冲区大小
|
|
17
|
-
* @param {Object} [logger] - 日志记录器
|
|
18
|
-
*/
|
|
19
|
-
constructor(storage, options = {}, logger) {
|
|
20
|
-
this.storage = storage;
|
|
21
|
-
this.buffer = [];
|
|
22
|
-
this.batchSize = options.batchSize || 10;
|
|
23
|
-
this.flushInterval = options.flushInterval || 5000;
|
|
24
|
-
this.maxBufferSize = options.maxBufferSize || 100;
|
|
25
|
-
this.timer = null;
|
|
26
|
-
this.flushing = false;
|
|
27
|
-
this.logger = logger || console;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 添加日志到队列
|
|
32
|
-
* @param {Object} log - 慢查询日志对象
|
|
33
|
-
* @returns {Promise<void>}
|
|
34
|
-
*/
|
|
35
|
-
async add(log) {
|
|
36
|
-
this.buffer.push(log);
|
|
37
|
-
|
|
38
|
-
// 防止内存溢出:达到最大缓冲区,立即刷新
|
|
39
|
-
if (this.buffer.length >= this.maxBufferSize) {
|
|
40
|
-
await this.flush();
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 达到批量大小,立即刷新
|
|
45
|
-
if (this.buffer.length >= this.batchSize) {
|
|
46
|
-
await this.flush();
|
|
47
|
-
} else if (!this.timer) {
|
|
48
|
-
// 启动定时器(防止数据积压)
|
|
49
|
-
this.timer = setTimeout(() => this.flush(), this.flushInterval);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 刷新队列(批量写入)
|
|
55
|
-
* @returns {Promise<void>}
|
|
56
|
-
*/
|
|
57
|
-
async flush() {
|
|
58
|
-
// 防止并发刷新
|
|
59
|
-
if (this.flushing || this.buffer.length === 0) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
this.flushing = true;
|
|
64
|
-
const logs = this.buffer.splice(0); // 清空缓冲区
|
|
65
|
-
clearTimeout(this.timer);
|
|
66
|
-
this.timer = null;
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
// 批量写入
|
|
70
|
-
await this.storage.saveBatch(logs);
|
|
71
|
-
if (this.logger.debug) {
|
|
72
|
-
this.logger.debug(`[SlowQueryLog] Batch flushed: ${logs.length} logs`);
|
|
73
|
-
}
|
|
74
|
-
} catch (err) {
|
|
75
|
-
// ⚠️ 失败不阻塞主流程,仅记录错误
|
|
76
|
-
if (this.logger.error) {
|
|
77
|
-
this.logger.error('[SlowQueryLog] Failed to save slow query logs batch:', err);
|
|
78
|
-
}
|
|
79
|
-
} finally {
|
|
80
|
-
this.flushing = false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* 关闭队列(确保数据不丢失)
|
|
86
|
-
* @returns {Promise<void>}
|
|
87
|
-
*/
|
|
88
|
-
async close() {
|
|
89
|
-
clearTimeout(this.timer);
|
|
90
|
-
this.timer = null;
|
|
91
|
-
await this.flush(); // 最后刷新一次
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
module.exports = { BatchQueue };
|
|
96
|
-
|
|
97
|
-
|