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.
Files changed (172) hide show
  1. package/CHANGELOG.md +56 -60
  2. package/LICENSE +201 -21
  3. package/README.md +537 -1828
  4. package/changelogs/README.md +160 -0
  5. package/changelogs/v2.0.0.md +222 -0
  6. package/dist/cjs/index.cjs +10600 -0
  7. package/dist/cjs/mongodb/common/transaction-aware.cjs +10 -0
  8. package/dist/cjs/transaction/CacheLockManager.cjs +100 -0
  9. package/dist/cjs/transaction/Transaction.cjs +158 -0
  10. package/dist/cjs/transaction/TransactionManager.cjs +298 -0
  11. package/dist/esm/index.mjs +10650 -0
  12. package/dist/types/base.d.ts +81 -0
  13. package/dist/types/collection.d.ts +1031 -0
  14. package/dist/types/expression.d.ts +115 -0
  15. package/dist/types/index.d.ts +23 -0
  16. package/dist/types/lock.d.ts +74 -0
  17. package/dist/types/model.d.ts +526 -0
  18. package/dist/types/mongodb.d.ts +49 -0
  19. package/dist/types/monsqlize.d.ts +491 -0
  20. package/dist/types/pool.d.ts +84 -0
  21. package/dist/types/runtime.d.ts +362 -0
  22. package/dist/types/saga.d.ts +143 -0
  23. package/dist/types/slow-query-log.d.ts +126 -0
  24. package/dist/types/sync.d.ts +103 -0
  25. package/dist/types/transaction.d.ts +132 -0
  26. package/package.json +67 -69
  27. package/index.d.ts +0 -206
  28. package/index.mjs +0 -52
  29. package/lib/cache-invalidation.js +0 -279
  30. package/lib/cache.js +0 -530
  31. package/lib/common/cursor.js +0 -59
  32. package/lib/common/docs-urls.js +0 -73
  33. package/lib/common/index-options.js +0 -223
  34. package/lib/common/log.js +0 -61
  35. package/lib/common/namespace.js +0 -22
  36. package/lib/common/normalize.js +0 -34
  37. package/lib/common/page-result.js +0 -43
  38. package/lib/common/runner.js +0 -57
  39. package/lib/common/server-features.js +0 -232
  40. package/lib/common/shape-builders.js +0 -27
  41. package/lib/common/validation.js +0 -113
  42. package/lib/connect.js +0 -99
  43. package/lib/constants.js +0 -55
  44. package/lib/count-queue.js +0 -188
  45. package/lib/distributed-cache-invalidator.js +0 -260
  46. package/lib/errors.js +0 -168
  47. package/lib/expression/cache/ExpressionCache.js +0 -114
  48. package/lib/expression/compiler/ExpressionCompiler.js +0 -1090
  49. package/lib/expression/compiler/ExpressionCompilerExtensions.js +0 -531
  50. package/lib/expression/detector.js +0 -84
  51. package/lib/expression/factory.js +0 -29
  52. package/lib/expression/index.js +0 -19
  53. package/lib/function-cache.js +0 -533
  54. package/lib/index.js +0 -1251
  55. package/lib/infrastructure/ConnectionPoolManager.js +0 -464
  56. package/lib/infrastructure/HealthChecker.js +0 -281
  57. package/lib/infrastructure/PoolConfig.js +0 -199
  58. package/lib/infrastructure/PoolSelector.js +0 -225
  59. package/lib/infrastructure/PoolStats.js +0 -244
  60. package/lib/infrastructure/ssh-tunnel-ssh2.js +0 -212
  61. package/lib/infrastructure/ssh-tunnel.js +0 -41
  62. package/lib/infrastructure/uri-parser.js +0 -36
  63. package/lib/lock/Lock.js +0 -67
  64. package/lib/lock/errors.js +0 -28
  65. package/lib/lock/index.js +0 -13
  66. package/lib/logger.js +0 -225
  67. package/lib/model/examples/test.js +0 -311
  68. package/lib/model/features/defaults.js +0 -161
  69. package/lib/model/features/populate.js +0 -568
  70. package/lib/model/features/relations.js +0 -120
  71. package/lib/model/features/soft-delete.js +0 -349
  72. package/lib/model/features/version.js +0 -157
  73. package/lib/model/features/virtuals.js +0 -219
  74. package/lib/model/index.js +0 -1265
  75. package/lib/mongodb/common/accessor-helpers.js +0 -59
  76. package/lib/mongodb/common/agg-pipeline.js +0 -36
  77. package/lib/mongodb/common/aggregation-validator.js +0 -127
  78. package/lib/mongodb/common/iid.js +0 -28
  79. package/lib/mongodb/common/lexicographic-expr.js +0 -53
  80. package/lib/mongodb/common/shape.js +0 -32
  81. package/lib/mongodb/common/sort.js +0 -39
  82. package/lib/mongodb/common/transaction-aware.js +0 -25
  83. package/lib/mongodb/connect.js +0 -234
  84. package/lib/mongodb/index.js +0 -639
  85. package/lib/mongodb/management/admin-ops.js +0 -200
  86. package/lib/mongodb/management/bookmark-ops.js +0 -167
  87. package/lib/mongodb/management/cache-ops.js +0 -50
  88. package/lib/mongodb/management/collection-ops.js +0 -387
  89. package/lib/mongodb/management/database-ops.js +0 -202
  90. package/lib/mongodb/management/index-ops.js +0 -475
  91. package/lib/mongodb/management/index.js +0 -17
  92. package/lib/mongodb/management/namespace.js +0 -31
  93. package/lib/mongodb/management/validation-ops.js +0 -268
  94. package/lib/mongodb/queries/aggregate.js +0 -172
  95. package/lib/mongodb/queries/chain.js +0 -631
  96. package/lib/mongodb/queries/count.js +0 -99
  97. package/lib/mongodb/queries/distinct.js +0 -78
  98. package/lib/mongodb/queries/find-and-count.js +0 -193
  99. package/lib/mongodb/queries/find-by-ids.js +0 -236
  100. package/lib/mongodb/queries/find-one-by-id.js +0 -171
  101. package/lib/mongodb/queries/find-one.js +0 -71
  102. package/lib/mongodb/queries/find-page.js +0 -618
  103. package/lib/mongodb/queries/find.js +0 -171
  104. package/lib/mongodb/queries/index.js +0 -51
  105. package/lib/mongodb/queries/watch.js +0 -538
  106. package/lib/mongodb/writes/common/batch-retry.js +0 -65
  107. package/lib/mongodb/writes/delete-batch.js +0 -323
  108. package/lib/mongodb/writes/delete-many.js +0 -181
  109. package/lib/mongodb/writes/delete-one.js +0 -173
  110. package/lib/mongodb/writes/find-one-and-delete.js +0 -203
  111. package/lib/mongodb/writes/find-one-and-replace.js +0 -239
  112. package/lib/mongodb/writes/find-one-and-update.js +0 -240
  113. package/lib/mongodb/writes/increment-one.js +0 -259
  114. package/lib/mongodb/writes/index.js +0 -46
  115. package/lib/mongodb/writes/insert-batch.js +0 -508
  116. package/lib/mongodb/writes/insert-many.js +0 -223
  117. package/lib/mongodb/writes/insert-one.js +0 -169
  118. package/lib/mongodb/writes/replace-one.js +0 -226
  119. package/lib/mongodb/writes/result-handler.js +0 -237
  120. package/lib/mongodb/writes/update-batch.js +0 -416
  121. package/lib/mongodb/writes/update-many.js +0 -275
  122. package/lib/mongodb/writes/update-one.js +0 -273
  123. package/lib/mongodb/writes/upsert-one.js +0 -203
  124. package/lib/multi-level-cache.js +0 -244
  125. package/lib/operators.js +0 -330
  126. package/lib/redis-cache-adapter.js +0 -267
  127. package/lib/saga/SagaContext.js +0 -67
  128. package/lib/saga/SagaDefinition.js +0 -32
  129. package/lib/saga/SagaExecutor.js +0 -201
  130. package/lib/saga/SagaOrchestrator.js +0 -186
  131. package/lib/saga/index.js +0 -11
  132. package/lib/slow-query-log/base-storage.js +0 -70
  133. package/lib/slow-query-log/batch-queue.js +0 -97
  134. package/lib/slow-query-log/config-manager.js +0 -196
  135. package/lib/slow-query-log/index.js +0 -238
  136. package/lib/slow-query-log/mongodb-storage.js +0 -324
  137. package/lib/slow-query-log/query-hash.js +0 -39
  138. package/lib/sync/ChangeStreamSyncManager.js +0 -405
  139. package/lib/sync/ResumeTokenStore.js +0 -192
  140. package/lib/sync/SyncConfig.js +0 -127
  141. package/lib/sync/SyncTarget.js +0 -240
  142. package/lib/sync/index.js +0 -20
  143. package/lib/transaction/CacheLockManager.js +0 -162
  144. package/lib/transaction/DistributedCacheLockManager.js +0 -475
  145. package/lib/transaction/Transaction.js +0 -315
  146. package/lib/transaction/TransactionManager.js +0 -267
  147. package/lib/transaction/index.js +0 -11
  148. package/lib/utils/objectid-converter.js +0 -632
  149. package/types/README.md +0 -122
  150. package/types/base.ts +0 -94
  151. package/types/batch.ts +0 -187
  152. package/types/cache.ts +0 -71
  153. package/types/chain.ts +0 -254
  154. package/types/collection.ts +0 -357
  155. package/types/expression.ts +0 -109
  156. package/types/function-cache.d.ts +0 -135
  157. package/types/lock.ts +0 -95
  158. package/types/model/definition.ts +0 -152
  159. package/types/model/index.ts +0 -10
  160. package/types/model/instance.ts +0 -121
  161. package/types/model/relations.ts +0 -121
  162. package/types/model/virtuals.ts +0 -32
  163. package/types/monsqlize.ts +0 -245
  164. package/types/options.ts +0 -192
  165. package/types/pagination.ts +0 -154
  166. package/types/pool.ts +0 -125
  167. package/types/query.ts +0 -71
  168. package/types/saga.ts +0 -125
  169. package/types/stream.ts +0 -64
  170. package/types/sync.ts +0 -79
  171. package/types/transaction.ts +0 -79
  172. package/types/write.ts +0 -77
@@ -1,127 +0,0 @@
1
- /**
2
- * SyncConfig - 同步配置验证
3
- *
4
- * 负责验证和规范化 Change Stream 同步配置
5
- *
6
- * @module lib/sync/SyncConfig
7
- * @since v1.0.8
8
- */
9
-
10
- /**
11
- * 验证同步配置
12
- *
13
- * @param {Object} config - 同步配置
14
- * @param {boolean} config.enabled - 是否启用同步
15
- * @param {Array} config.targets - 备份目标数组
16
- * @param {Object} [config.resumeToken] - Resume Token 配置
17
- * @param {Function} [config.filter] - 过滤函数
18
- * @param {Function} [config.transform] - 转换函数
19
- * @throws {Error} 配置无效时抛出错误
20
- */
21
- function validateSyncConfig(config) {
22
- if (!config || typeof config !== 'object') {
23
- throw new Error('[Sync] 配置必须是对象');
24
- }
25
-
26
- // 验证 enabled
27
- if (typeof config.enabled !== 'boolean') {
28
- throw new Error('[Sync] enabled 必须是 boolean 类型');
29
- }
30
-
31
- // 如果未启用,不需要验证其他配置
32
- if (!config.enabled) {
33
- return;
34
- }
35
-
36
- // 验证 targets
37
- if (!Array.isArray(config.targets) || config.targets.length === 0) {
38
- throw new Error('[Sync] targets 必须是非空数组');
39
- }
40
-
41
- // 验证每个 target
42
- config.targets.forEach((target, index) => {
43
- validateTargetConfig(target, index);
44
- });
45
-
46
- // 验证 resumeToken(可选)
47
- if (config.resumeToken) {
48
- validateResumeTokenConfig(config.resumeToken);
49
- }
50
-
51
- // 验证 filter(可选)
52
- if (config.filter && typeof config.filter !== 'function') {
53
- throw new Error('[Sync] filter 必须是函数');
54
- }
55
-
56
- // 验证 transform(可选)
57
- if (config.transform && typeof config.transform !== 'function') {
58
- throw new Error('[Sync] transform 必须是函数');
59
- }
60
- }
61
-
62
- /**
63
- * 验证备份目标配置
64
- *
65
- * @param {Object} target - 目标配置
66
- * @param {number} index - 索引(用于错误提示)
67
- */
68
- function validateTargetConfig(target, index) {
69
- if (!target || typeof target !== 'object') {
70
- throw new Error(`[Sync] targets[${index}] 必须是对象`);
71
- }
72
-
73
- // 验证 name
74
- if (!target.name || typeof target.name !== 'string') {
75
- throw new Error(`[Sync] targets[${index}].name 必须是非空字符串`);
76
- }
77
-
78
- // 验证 uri
79
- if (!target.uri || typeof target.uri !== 'string') {
80
- throw new Error(`[Sync] targets[${index}].uri 必须是非空字符串`);
81
- }
82
-
83
- // 验证 collections(可选)
84
- if (target.collections) {
85
- if (!Array.isArray(target.collections)) {
86
- throw new Error(`[Sync] targets[${index}].collections 必须是数组`);
87
- }
88
- if (target.collections.length === 0) {
89
- throw new Error(`[Sync] targets[${index}].collections 不能为空数组`);
90
- }
91
- }
92
- }
93
-
94
- /**
95
- * 验证 Resume Token 配置
96
- *
97
- * @param {Object} config - Resume Token 配置
98
- */
99
- function validateResumeTokenConfig(config) {
100
- if (!config || typeof config !== 'object') {
101
- throw new Error('[Sync] resumeToken 必须是对象');
102
- }
103
-
104
- // 验证 storage
105
- const validStorages = ['file', 'redis'];
106
- if (config.storage && !validStorages.includes(config.storage)) {
107
- throw new Error(`[Sync] resumeToken.storage 必须是 ${validStorages.join(' 或 ')}`);
108
- }
109
-
110
- // 验证 path(文件模式)
111
- if (config.storage === 'file' && config.path && typeof config.path !== 'string') {
112
- throw new Error('[Sync] resumeToken.path 必须是字符串');
113
- }
114
-
115
- // 验证 redis(Redis 模式)
116
- if (config.storage === 'redis' && config.redis && typeof config.redis !== 'object') {
117
- throw new Error('[Sync] resumeToken.redis 必须是对象');
118
- }
119
- }
120
-
121
- module.exports = {
122
- validateSyncConfig,
123
- validateTargetConfig,
124
- validateResumeTokenConfig
125
- };
126
-
127
-
@@ -1,240 +0,0 @@
1
- /**
2
- * SyncTarget - 备份目标
3
- *
4
- * 负责连接备份数据库并执行同步操作
5
- * 复用 ConnectionPoolManager 管理连接
6
- *
7
- * @module lib/sync/SyncTarget
8
- * @since v1.0.8
9
- */
10
-
11
- /**
12
- * 同步目标类
13
- */
14
- class SyncTarget {
15
- /**
16
- * 构造函数
17
- *
18
- * @param {Object} options - 配置选项
19
- * @param {string} options.name - 目标名称
20
- * @param {Object} options.poolManager - ConnectionPoolManager 实例
21
- * @param {Object} options.config - 目标配置
22
- * @param {string} options.config.uri - MongoDB URI
23
- * @param {Array} [options.config.collections] - 同步的集合列表
24
- * @param {Object} [options.config.healthCheck] - 健康检查配置
25
- * @param {Object} [options.logger] - 日志记录器
26
- */
27
- constructor(options) {
28
- this.name = options.name;
29
- this.poolManager = options.poolManager;
30
- this.config = options.config;
31
- this.logger = options.logger || console;
32
-
33
- this.client = null;
34
- this.db = null;
35
- this.collections = new Map(); // 缓存 collection 对象
36
-
37
- this.stats = {
38
- syncCount: 0,
39
- errorCount: 0,
40
- lastSyncTime: null,
41
- lastError: null
42
- };
43
- }
44
-
45
- /**
46
- * 连接备份数据库
47
- *
48
- * 复用 ConnectionPoolManager,将备份库添加为连接池
49
- *
50
- * @returns {Promise<void>}
51
- */
52
- async connect() {
53
- try {
54
- // 🔴 关键:将备份库添加到 ConnectionPoolManager
55
- await this.poolManager.addPool({
56
- name: this.name,
57
- uri: this.config.uri,
58
- role: 'backup', // 标记为备份角色
59
- healthCheck: this.config.healthCheck || {
60
- enabled: true,
61
- interval: 30000, // 30秒检查一次
62
- timeout: 5000,
63
- retries: 3
64
- }
65
- });
66
-
67
- // 获取连接
68
- const pool = this.poolManager.getPool(this.name);
69
- this.client = pool.client;
70
- this.db = this.client.db();
71
-
72
- this.logger.info('[SyncTarget] 备份库已连接', {
73
- name: this.name,
74
- uri: this._maskUri(this.config.uri)
75
- });
76
-
77
- } catch (error) {
78
- this.logger.error('[SyncTarget] 连接备份库失败', {
79
- name: this.name,
80
- error: error.message
81
- });
82
- throw error;
83
- }
84
- }
85
-
86
- /**
87
- * 应用同步操作
88
- *
89
- * @param {string} operationType - 操作类型 ('insert' | 'update' | 'replace' | 'delete')
90
- * @param {Object} document - 文档对象
91
- * @param {Object} documentKey - 文档键 { _id, ns }
92
- * @returns {Promise<void>}
93
- */
94
- async apply(operationType, document, documentKey) {
95
- const collectionName = documentKey?.ns?.coll || this.config.collection;
96
-
97
- if (!collectionName) {
98
- this.logger.warn('[SyncTarget] 无法确定集合名称', {
99
- target: this.name,
100
- documentKey
101
- });
102
- return;
103
- }
104
-
105
- const collection = this._getCollection(collectionName);
106
-
107
- try {
108
- switch (operationType) {
109
- case 'insert':
110
- await collection.insertOne(document);
111
- break;
112
-
113
- case 'update':
114
- case 'replace':
115
- // 使用 replaceOne + upsert 确保数据一致
116
- await collection.replaceOne(
117
- { _id: documentKey._id },
118
- document,
119
- { upsert: true }
120
- );
121
- break;
122
-
123
- case 'delete':
124
- await collection.deleteOne({ _id: documentKey._id });
125
- break;
126
-
127
- default:
128
- this.logger.warn('[SyncTarget] 未知操作类型', {
129
- target: this.name,
130
- operationType
131
- });
132
- return;
133
- }
134
-
135
- // 更新统计
136
- this.stats.syncCount++;
137
- this.stats.lastSyncTime = new Date();
138
-
139
- this.logger.debug('[SyncTarget] 同步成功', {
140
- target: this.name,
141
- operation: operationType,
142
- collection: collectionName,
143
- id: documentKey._id
144
- });
145
-
146
- } catch (error) {
147
- // 更新统计
148
- this.stats.errorCount++;
149
- this.stats.lastError = {
150
- time: new Date(),
151
- message: error.message,
152
- operation: operationType,
153
- collection: collectionName
154
- };
155
-
156
- this.logger.error('[SyncTarget] 同步失败', {
157
- target: this.name,
158
- operation: operationType,
159
- collection: collectionName,
160
- error: error.message,
161
- code: error.code
162
- });
163
-
164
- // 抛出错误,由 ChangeStreamSyncManager 处理
165
- throw error;
166
- }
167
- }
168
-
169
- /**
170
- * 获取 Collection 对象(带缓存)
171
- *
172
- * @private
173
- * @param {string} name - 集合名称
174
- * @returns {Object} MongoDB Collection 对象
175
- */
176
- _getCollection(name) {
177
- if (!this.collections.has(name)) {
178
- this.collections.set(name, this.db.collection(name));
179
- }
180
- return this.collections.get(name);
181
- }
182
-
183
- /**
184
- * 掩码 URI(隐藏密码)
185
- *
186
- * @private
187
- * @param {string} uri - MongoDB URI
188
- * @returns {string} 掩码后的 URI
189
- */
190
- _maskUri(uri) {
191
- try {
192
- return uri.replace(/:([^:@]+)@/, ':***@');
193
- } catch (error) {
194
- return uri;
195
- }
196
- }
197
-
198
- /**
199
- * 获取统计信息
200
- *
201
- * @returns {Object} 统计信息
202
- */
203
- getStats() {
204
- return {
205
- name: this.name,
206
- syncCount: this.stats.syncCount,
207
- errorCount: this.stats.errorCount,
208
- lastSyncTime: this.stats.lastSyncTime,
209
- lastError: this.stats.lastError,
210
- successRate: this.stats.syncCount > 0
211
- ? ((this.stats.syncCount - this.stats.errorCount) / this.stats.syncCount * 100).toFixed(2) + '%'
212
- : '0%'
213
- };
214
- }
215
-
216
- /**
217
- * 关闭连接
218
- *
219
- * @returns {Promise<void>}
220
- */
221
- async close() {
222
- try {
223
- if (this.poolManager && this.name) {
224
- await this.poolManager.removePool(this.name);
225
- this.logger.info('[SyncTarget] 备份库连接已关闭', {
226
- name: this.name
227
- });
228
- }
229
- } catch (error) {
230
- this.logger.warn('[SyncTarget] 关闭连接失败', {
231
- name: this.name,
232
- error: error.message
233
- });
234
- }
235
- }
236
- }
237
-
238
- module.exports = SyncTarget;
239
-
240
-
package/lib/sync/index.js DELETED
@@ -1,20 +0,0 @@
1
- /**
2
- * Sync 模块导出
3
- *
4
- * @module lib/sync
5
- * @since v1.0.9
6
- */
7
-
8
- const ChangeStreamSyncManager = require('./ChangeStreamSyncManager');
9
- const SyncTarget = require('./SyncTarget');
10
- const ResumeTokenStore = require('./ResumeTokenStore');
11
- const { validateSyncConfig } = require('./SyncConfig');
12
-
13
- module.exports = {
14
- ChangeStreamSyncManager,
15
- SyncTarget,
16
- ResumeTokenStore,
17
- validateSyncConfig
18
- };
19
-
20
-
@@ -1,162 +0,0 @@
1
- /**
2
- * 缓存锁管理器
3
- * 用于在事务执行期间锁定缓存键,防止脏数据写入缓存
4
- */
5
-
6
- class CacheLockManager {
7
- constructor(options = {}) {
8
- this.locks = new Map(); // key -> { sessionId, expiresAt }
9
- this.maxDuration = options.maxDuration || 300000; // 5分钟默认
10
- this.lockCleanupInterval = options.lockCleanupInterval || 10000; // 10秒清理一次
11
- this.cleanupTimer = null;
12
-
13
- // 启动自动清理
14
- this._startCleanup();
15
- }
16
-
17
- /**
18
- * 添加缓存锁
19
- * @param {string} key - 缓存键(支持通配符 *)
20
- * @param {Object} session - MongoDB session 对象
21
- */
22
- addLock(key, session) {
23
- if (!session || !session.id) {
24
- return;
25
- }
26
-
27
- const sessionId = session.id.toString();
28
- const expiresAt = Date.now() + this.maxDuration;
29
-
30
- this.locks.set(key, {
31
- sessionId,
32
- expiresAt,
33
- lockedAt: Date.now()
34
- });
35
- }
36
-
37
- /**
38
- * 检查缓存键是否被锁定
39
- * @param {string} key - 缓存键
40
- * @returns {boolean}
41
- */
42
- isLocked(key) {
43
- // 精确匹配
44
- if (this.locks.has(key)) {
45
- const lock = this.locks.get(key);
46
- if (Date.now() < lock.expiresAt) {
47
- return true;
48
- }
49
- // 过期自动删除
50
- this.locks.delete(key);
51
- }
52
-
53
- // 通配符匹配
54
- for (const [lockKey, lock] of this.locks.entries()) {
55
- if (lockKey.includes('*')) {
56
- const pattern = lockKey.replace(/\*/g, '.*');
57
- const regex = new RegExp(`^${pattern}$`);
58
- if (regex.test(key)) {
59
- if (Date.now() < lock.expiresAt) {
60
- return true;
61
- }
62
- // 过期自动删除
63
- this.locks.delete(lockKey);
64
- }
65
- }
66
- }
67
-
68
- return false;
69
- }
70
-
71
- /**
72
- * 释放指定 session 的所有锁
73
- * @param {Object} session - MongoDB session 对象
74
- */
75
- releaseLocks(session) {
76
- if (!session || !session.id) {
77
- return;
78
- }
79
-
80
- const sessionId = session.id.toString();
81
- const keysToDelete = [];
82
-
83
- for (const [key, lock] of this.locks.entries()) {
84
- if (lock.sessionId === sessionId) {
85
- keysToDelete.push(key);
86
- }
87
- }
88
-
89
- keysToDelete.forEach(key => this.locks.delete(key));
90
- }
91
-
92
- /**
93
- * 清理过期的锁
94
- * @private
95
- */
96
- _cleanupExpiredLocks() {
97
- const now = Date.now();
98
- const keysToDelete = [];
99
-
100
- for (const [key, lock] of this.locks.entries()) {
101
- if (now >= lock.expiresAt) {
102
- keysToDelete.push(key);
103
- }
104
- }
105
-
106
- if (keysToDelete.length > 0) {
107
- keysToDelete.forEach(key => this.locks.delete(key));
108
- }
109
- }
110
-
111
- /**
112
- * 启动自动清理定时器
113
- * @private
114
- */
115
- _startCleanup() {
116
- if (this.cleanupTimer) {
117
- return;
118
- }
119
-
120
- this.cleanupTimer = setInterval(() => {
121
- this._cleanupExpiredLocks();
122
- }, this.lockCleanupInterval);
123
-
124
- // 防止定时器阻止进程退出
125
- if (this.cleanupTimer.unref) {
126
- this.cleanupTimer.unref();
127
- }
128
- }
129
-
130
- /**
131
- * 停止自动清理
132
- */
133
- stop() {
134
- if (this.cleanupTimer) {
135
- clearInterval(this.cleanupTimer);
136
- this.cleanupTimer = null;
137
- }
138
- }
139
-
140
- /**
141
- * 获取当前锁的统计信息
142
- */
143
- getStats() {
144
- return {
145
- totalLocks: this.locks.size,
146
- activeLocks: Array.from(this.locks.values()).filter(
147
- lock => Date.now() < lock.expiresAt
148
- ).length
149
- };
150
- }
151
-
152
- /**
153
- * 清除所有锁(用于测试)
154
- */
155
- clear() {
156
- this.locks.clear();
157
- }
158
- }
159
-
160
- module.exports = CacheLockManager;
161
-
162
-