atomic-queues 2.3.0 → 3.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/README.md +297 -382
- package/dist/cli/generators/classes.d.ts +1 -1
- package/dist/cli/generators/json-schema.d.ts +1 -1
- package/dist/cli/generators/typescript.d.ts +1 -1
- package/dist/cli/index.js +147 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/cluster/cluster-discovery.service.d.ts +91 -0
- package/dist/cluster/cluster-discovery.service.d.ts.map +1 -0
- package/dist/cluster/cluster-discovery.service.js +423 -0
- package/dist/cluster/cluster-discovery.service.js.map +1 -0
- package/dist/cluster/grpc-peer-monitor.service.d.ts +31 -0
- package/dist/cluster/grpc-peer-monitor.service.d.ts.map +1 -0
- package/dist/cluster/grpc-peer-monitor.service.js +192 -0
- package/dist/cluster/grpc-peer-monitor.service.js.map +1 -0
- package/dist/cluster/index.d.ts +7 -0
- package/dist/cluster/index.d.ts.map +1 -0
- package/dist/cluster/index.js +23 -0
- package/dist/cluster/index.js.map +1 -0
- package/dist/cluster/leader-election.service.d.ts +38 -0
- package/dist/cluster/leader-election.service.d.ts.map +1 -0
- package/dist/cluster/leader-election.service.js +184 -0
- package/dist/cluster/leader-election.service.js.map +1 -0
- package/dist/cluster/master-coordinator.d.ts +50 -0
- package/dist/cluster/master-coordinator.d.ts.map +1 -0
- package/dist/cluster/master-coordinator.js +307 -0
- package/dist/cluster/master-coordinator.js.map +1 -0
- package/dist/cluster/redis-health-monitor.service.d.ts +23 -0
- package/dist/cluster/redis-health-monitor.service.d.ts.map +1 -0
- package/dist/cluster/redis-health-monitor.service.js +100 -0
- package/dist/cluster/redis-health-monitor.service.js.map +1 -0
- package/dist/cluster/server-ring.service.d.ts +48 -0
- package/dist/cluster/server-ring.service.d.ts.map +1 -0
- package/dist/cluster/server-ring.service.js +136 -0
- package/dist/cluster/server-ring.service.js.map +1 -0
- package/dist/decorators/entity.decorators.d.ts +16 -24
- package/dist/decorators/entity.decorators.d.ts.map +1 -1
- package/dist/decorators/entity.decorators.js +0 -39
- package/dist/decorators/entity.decorators.js.map +1 -1
- package/dist/decorators/interfaces.d.ts +10 -10
- package/dist/decorators/interfaces.d.ts.map +1 -1
- package/dist/decorators/job.decorators.d.ts +4 -52
- package/dist/decorators/job.decorators.d.ts.map +1 -1
- package/dist/decorators/job.decorators.js +6 -54
- package/dist/decorators/job.decorators.js.map +1 -1
- package/dist/decorators/metadata-readers.d.ts +4 -2
- package/dist/decorators/metadata-readers.d.ts.map +1 -1
- package/dist/decorators/metadata-readers.js +2 -0
- package/dist/decorators/metadata-readers.js.map +1 -1
- package/dist/decorators/schema.decorators.d.ts +1 -1
- package/dist/decorators/schema.decorators.d.ts.map +1 -1
- package/dist/decorators/schema.decorators.js.map +1 -1
- package/dist/decorators/utils.d.ts +1 -1
- package/dist/decorators/utils.d.ts.map +1 -1
- package/dist/decorators/utils.js +5 -1
- package/dist/decorators/utils.js.map +1 -1
- package/dist/domain/interfaces/config.interfaces.d.ts +92 -29
- package/dist/domain/interfaces/config.interfaces.d.ts.map +1 -1
- package/dist/domain/interfaces/index.d.ts +1 -0
- package/dist/domain/interfaces/index.d.ts.map +1 -1
- package/dist/domain/interfaces/index.js +1 -0
- package/dist/domain/interfaces/index.js.map +1 -1
- package/dist/{services/registry → domain/interfaces}/registry.types.d.ts.map +1 -1
- package/dist/domain/interfaces/registry.types.js.map +1 -0
- package/dist/grpc/grpc-client-pool.service.d.ts +71 -0
- package/dist/grpc/grpc-client-pool.service.d.ts.map +1 -0
- package/dist/grpc/grpc-client-pool.service.js +307 -0
- package/dist/grpc/grpc-client-pool.service.js.map +1 -0
- package/dist/grpc/grpc-server.service.d.ts +47 -0
- package/dist/grpc/grpc-server.service.d.ts.map +1 -0
- package/dist/grpc/grpc-server.service.js +494 -0
- package/dist/grpc/grpc-server.service.js.map +1 -0
- package/dist/grpc/index.d.ts +3 -0
- package/dist/grpc/index.d.ts.map +1 -0
- package/dist/{services/executor-pool → grpc}/index.js +2 -1
- package/dist/grpc/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/module/atomic-queues.module.d.ts +1 -0
- package/dist/module/atomic-queues.module.d.ts.map +1 -1
- package/dist/module/atomic-queues.module.js +59 -10
- package/dist/module/atomic-queues.module.js.map +1 -1
- package/dist/services/command-discovery/command-discovery.service.js +2 -2
- package/dist/services/command-discovery/command-discovery.service.js.map +1 -1
- package/dist/services/index.d.ts +2 -8
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +2 -8
- package/dist/services/index.js.map +1 -1
- package/dist/services/message-router/index.d.ts +2 -0
- package/dist/services/message-router/index.d.ts.map +1 -0
- package/dist/services/{actor-system → message-router}/index.js +1 -1
- package/dist/services/message-router/index.js.map +1 -0
- package/dist/services/message-router/message-router.service.d.ts +53 -0
- package/dist/services/message-router/message-router.service.d.ts.map +1 -0
- package/dist/services/message-router/message-router.service.js +519 -0
- package/dist/services/message-router/message-router.service.js.map +1 -0
- package/dist/services/queue-bus/cluster-contracts.d.ts +1 -1
- package/dist/services/queue-bus/cluster-contracts.d.ts.map +1 -1
- package/dist/services/queue-bus/cluster-contracts.js.map +1 -1
- package/dist/services/queue-bus/queue-bus.service.d.ts +3 -21
- package/dist/services/queue-bus/queue-bus.service.d.ts.map +1 -1
- package/dist/services/queue-bus/queue-bus.service.js +15 -119
- package/dist/services/queue-bus/queue-bus.service.js.map +1 -1
- package/dist/utils/id.utils.d.ts +3 -0
- package/dist/utils/id.utils.d.ts.map +1 -0
- package/dist/utils/id.utils.js +14 -0
- package/dist/utils/id.utils.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/wal/index.d.ts +4 -0
- package/dist/wal/index.d.ts.map +1 -0
- package/dist/{services/gate → wal}/index.js +3 -1
- package/dist/wal/index.js.map +1 -0
- package/dist/wal/wal.scripts.d.ts +51 -0
- package/dist/wal/wal.scripts.d.ts.map +1 -0
- package/dist/wal/wal.scripts.js +84 -0
- package/dist/wal/wal.scripts.js.map +1 -0
- package/dist/wal/wal.service.d.ts +46 -0
- package/dist/wal/wal.service.d.ts.map +1 -0
- package/dist/wal/wal.service.js +243 -0
- package/dist/wal/wal.service.js.map +1 -0
- package/dist/wal/wal.types.d.ts +23 -0
- package/dist/wal/wal.types.d.ts.map +1 -0
- package/dist/wal/wal.types.js +3 -0
- package/dist/wal/wal.types.js.map +1 -0
- package/dist/workers/consistent-hash.d.ts +97 -0
- package/dist/workers/consistent-hash.d.ts.map +1 -0
- package/dist/workers/consistent-hash.js +231 -0
- package/dist/workers/consistent-hash.js.map +1 -0
- package/dist/workers/entity-worker-manager.d.ts +35 -0
- package/dist/workers/entity-worker-manager.d.ts.map +1 -0
- package/dist/workers/entity-worker-manager.js +237 -0
- package/dist/workers/entity-worker-manager.js.map +1 -0
- package/dist/workers/entity-worker.d.ts +54 -0
- package/dist/workers/entity-worker.d.ts.map +1 -0
- package/dist/workers/entity-worker.js +142 -0
- package/dist/workers/entity-worker.js.map +1 -0
- package/dist/workers/index.d.ts +4 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/{services/log → workers}/index.js +3 -1
- package/dist/workers/index.js.map +1 -0
- package/package.json +17 -4
- package/dist/services/actor-system/actor-system.service.d.ts +0 -19
- package/dist/services/actor-system/actor-system.service.d.ts.map +0 -1
- package/dist/services/actor-system/actor-system.service.js +0 -86
- package/dist/services/actor-system/actor-system.service.js.map +0 -1
- package/dist/services/actor-system/index.d.ts +0 -2
- package/dist/services/actor-system/index.d.ts.map +0 -1
- package/dist/services/actor-system/index.js.map +0 -1
- package/dist/services/executor-pool/executor-pool.service.d.ts +0 -38
- package/dist/services/executor-pool/executor-pool.service.d.ts.map +0 -1
- package/dist/services/executor-pool/executor-pool.service.js +0 -166
- package/dist/services/executor-pool/executor-pool.service.js.map +0 -1
- package/dist/services/executor-pool/index.d.ts +0 -2
- package/dist/services/executor-pool/index.d.ts.map +0 -1
- package/dist/services/executor-pool/index.js.map +0 -1
- package/dist/services/gate/gate.service.d.ts +0 -17
- package/dist/services/gate/gate.service.d.ts.map +0 -1
- package/dist/services/gate/gate.service.js +0 -81
- package/dist/services/gate/gate.service.js.map +0 -1
- package/dist/services/gate/index.d.ts +0 -2
- package/dist/services/gate/index.d.ts.map +0 -1
- package/dist/services/gate/index.js.map +0 -1
- package/dist/services/log/index.d.ts +0 -2
- package/dist/services/log/index.d.ts.map +0 -1
- package/dist/services/log/index.js.map +0 -1
- package/dist/services/log/log.service.d.ts +0 -21
- package/dist/services/log/log.service.d.ts.map +0 -1
- package/dist/services/log/log.service.js +0 -92
- package/dist/services/log/log.service.js.map +0 -1
- package/dist/services/registry/index.d.ts +0 -4
- package/dist/services/registry/index.d.ts.map +0 -1
- package/dist/services/registry/index.js +0 -20
- package/dist/services/registry/index.js.map +0 -1
- package/dist/services/registry/registry.service.d.ts +0 -43
- package/dist/services/registry/registry.service.d.ts.map +0 -1
- package/dist/services/registry/registry.service.js +0 -367
- package/dist/services/registry/registry.service.js.map +0 -1
- package/dist/services/registry/registry.types.js.map +0 -1
- package/dist/services/registry/schema-converter.d.ts +0 -2
- package/dist/services/registry/schema-converter.d.ts.map +0 -1
- package/dist/services/registry/schema-converter.js +0 -27
- package/dist/services/registry/schema-converter.js.map +0 -1
- package/dist/services/result-collector/index.d.ts +0 -2
- package/dist/services/result-collector/index.d.ts.map +0 -1
- package/dist/services/result-collector/index.js +0 -18
- package/dist/services/result-collector/index.js.map +0 -1
- package/dist/services/result-collector/result-collector.service.d.ts +0 -17
- package/dist/services/result-collector/result-collector.service.d.ts.map +0 -1
- package/dist/services/result-collector/result-collector.service.js +0 -92
- package/dist/services/result-collector/result-collector.service.js.map +0 -1
- package/dist/services/scheduler/index.d.ts +0 -2
- package/dist/services/scheduler/index.d.ts.map +0 -1
- package/dist/services/scheduler/index.js +0 -18
- package/dist/services/scheduler/index.js.map +0 -1
- package/dist/services/scheduler/scheduler.service.d.ts +0 -17
- package/dist/services/scheduler/scheduler.service.d.ts.map +0 -1
- package/dist/services/scheduler/scheduler.service.js +0 -140
- package/dist/services/scheduler/scheduler.service.js.map +0 -1
- /package/dist/{services/registry → domain/interfaces}/registry.types.d.ts +0 -0
- /package/dist/{services/registry → domain/interfaces}/registry.types.js +0 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WalService = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const wal_scripts_1 = require("./wal.scripts");
|
|
7
|
+
/**
|
|
8
|
+
* Write-Ahead Log service.
|
|
9
|
+
*
|
|
10
|
+
* Constructed via factory in the module (not via DI injection decorators)
|
|
11
|
+
* because it needs a serverId that's generated at startup.
|
|
12
|
+
*/
|
|
13
|
+
class WalService {
|
|
14
|
+
constructor(redis, config, serverId) {
|
|
15
|
+
this.redis = redis;
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.logger = new common_1.Logger(WalService.name);
|
|
18
|
+
this.cleanupTimer = null;
|
|
19
|
+
this.deadLetterCallbacks = [];
|
|
20
|
+
this.keyPrefix = (0, utils_1.resolveKeyPrefix)(config);
|
|
21
|
+
this.serverId = serverId;
|
|
22
|
+
this.entryTTL = config.wal?.entryTTL ?? 86400;
|
|
23
|
+
this.cleanupInterval = config.wal?.cleanupInterval ?? 5000;
|
|
24
|
+
}
|
|
25
|
+
// =========================================================================
|
|
26
|
+
// KEY HELPERS
|
|
27
|
+
// =========================================================================
|
|
28
|
+
walEntryKey(entityKey, messageId) {
|
|
29
|
+
return `${this.keyPrefix}:wal:${this.serverId}:${entityKey}:${messageId}`;
|
|
30
|
+
}
|
|
31
|
+
walIndexKey() {
|
|
32
|
+
return `${this.keyPrefix}:wal:${this.serverId}:index`;
|
|
33
|
+
}
|
|
34
|
+
deadLetterKey(entityType) {
|
|
35
|
+
return `${this.keyPrefix}:dead:${entityType}`;
|
|
36
|
+
}
|
|
37
|
+
// =========================================================================
|
|
38
|
+
// WRITE — enqueue a message to the WAL
|
|
39
|
+
// =========================================================================
|
|
40
|
+
async write(entityKey, message) {
|
|
41
|
+
const entryKey = this.walEntryKey(entityKey, message.id);
|
|
42
|
+
const indexKey = this.walIndexKey();
|
|
43
|
+
const indexMember = `${entityKey}:${message.id}`;
|
|
44
|
+
const entry = {
|
|
45
|
+
state: 'enqueued',
|
|
46
|
+
message: JSON.stringify(message),
|
|
47
|
+
entity_key: entityKey,
|
|
48
|
+
enqueued_at: message.enqueuedAt.toString(),
|
|
49
|
+
correlation_id: message.correlationId ?? '',
|
|
50
|
+
server_id: this.serverId,
|
|
51
|
+
};
|
|
52
|
+
const pipeline = this.redis.pipeline();
|
|
53
|
+
pipeline.hset(entryKey, entry);
|
|
54
|
+
pipeline.expire(entryKey, this.entryTTL);
|
|
55
|
+
pipeline.zadd(indexKey, message.enqueuedAt, indexMember);
|
|
56
|
+
await pipeline.exec();
|
|
57
|
+
}
|
|
58
|
+
// =========================================================================
|
|
59
|
+
// STATE TRANSITIONS — atomic via Lua scripts
|
|
60
|
+
// =========================================================================
|
|
61
|
+
async markDispatched(entityKey, messageId, workerId) {
|
|
62
|
+
const entryKey = this.walEntryKey(entityKey, messageId);
|
|
63
|
+
const result = (await this.redis.eval(wal_scripts_1.DISPATCH_SCRIPT, 1, entryKey, Date.now().toString(), workerId.toString()));
|
|
64
|
+
return result === 1;
|
|
65
|
+
}
|
|
66
|
+
async markCompleted(entityKey, messageId) {
|
|
67
|
+
const entryKey = this.walEntryKey(entityKey, messageId);
|
|
68
|
+
const indexKey = this.walIndexKey();
|
|
69
|
+
const indexMember = `${entityKey}:${messageId}`;
|
|
70
|
+
const result = (await this.redis.eval(wal_scripts_1.COMPLETE_SCRIPT, 2, entryKey, indexKey, Date.now().toString(), indexMember));
|
|
71
|
+
return result === 1;
|
|
72
|
+
}
|
|
73
|
+
async markFailed(entityKey, messageId, error, stack) {
|
|
74
|
+
const entryKey = this.walEntryKey(entityKey, messageId);
|
|
75
|
+
const result = (await this.redis.eval(wal_scripts_1.FAIL_SCRIPT, 1, entryKey, Date.now().toString(), error, stack ?? ''));
|
|
76
|
+
return result === 1;
|
|
77
|
+
}
|
|
78
|
+
async markInterrupted(entityKey, messageId, reason) {
|
|
79
|
+
const entryKey = this.walEntryKey(entityKey, messageId);
|
|
80
|
+
const result = (await this.redis.eval(wal_scripts_1.INTERRUPT_SCRIPT, 1, entryKey, Date.now().toString(), reason));
|
|
81
|
+
return result === 1;
|
|
82
|
+
}
|
|
83
|
+
// =========================================================================
|
|
84
|
+
// READ — get a WAL entry
|
|
85
|
+
// =========================================================================
|
|
86
|
+
async getEntry(entityKey, messageId) {
|
|
87
|
+
const entryKey = this.walEntryKey(entityKey, messageId);
|
|
88
|
+
const raw = await this.redis.hgetall(entryKey);
|
|
89
|
+
if (!raw || !raw.state)
|
|
90
|
+
return null;
|
|
91
|
+
return {
|
|
92
|
+
messageId,
|
|
93
|
+
state: raw.state,
|
|
94
|
+
message: JSON.parse(raw.message),
|
|
95
|
+
entityKey: raw.entity_key,
|
|
96
|
+
serverId: raw.server_id,
|
|
97
|
+
enqueuedAt: parseInt(raw.enqueued_at, 10),
|
|
98
|
+
dispatchedAt: raw.dispatched_at ? parseInt(raw.dispatched_at, 10) : undefined,
|
|
99
|
+
completedAt: raw.completed_at ? parseInt(raw.completed_at, 10) : undefined,
|
|
100
|
+
error: raw.error || undefined,
|
|
101
|
+
errorStack: raw.error_stack || undefined,
|
|
102
|
+
correlationId: raw.correlation_id || undefined,
|
|
103
|
+
workerId: raw.worker_id ? parseInt(raw.worker_id, 10) : undefined,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// =========================================================================
|
|
107
|
+
// RECOVERY — run on startup to resolve orphaned entries
|
|
108
|
+
// =========================================================================
|
|
109
|
+
async recover() {
|
|
110
|
+
const indexKey = this.walIndexKey();
|
|
111
|
+
const members = await this.redis.zrange(indexKey, 0, -1);
|
|
112
|
+
let reEnqueued = 0;
|
|
113
|
+
let interrupted = 0;
|
|
114
|
+
let cleaned = 0;
|
|
115
|
+
for (const member of members) {
|
|
116
|
+
const parts = member.split(':');
|
|
117
|
+
const messageId = parts[parts.length - 1];
|
|
118
|
+
const entityKey = parts.slice(0, -1).join(':');
|
|
119
|
+
const entry = await this.getEntry(entityKey, messageId);
|
|
120
|
+
if (!entry) {
|
|
121
|
+
await this.redis.zrem(indexKey, member);
|
|
122
|
+
cleaned++;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
switch (entry.state) {
|
|
126
|
+
case 'enqueued':
|
|
127
|
+
reEnqueued++;
|
|
128
|
+
break;
|
|
129
|
+
case 'dispatched': {
|
|
130
|
+
await this.deadLetter(entry.message.entityType, entry.message, 'interrupted: process crashed during execution');
|
|
131
|
+
interrupted++;
|
|
132
|
+
const entryKey = this.walEntryKey(entityKey, messageId);
|
|
133
|
+
await this.redis.del(entryKey);
|
|
134
|
+
await this.redis.zrem(indexKey, member);
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
case 'completed':
|
|
138
|
+
case 'failed':
|
|
139
|
+
case 'interrupted': {
|
|
140
|
+
const entryKey = this.walEntryKey(entityKey, messageId);
|
|
141
|
+
await this.redis.del(entryKey);
|
|
142
|
+
await this.redis.zrem(indexKey, member);
|
|
143
|
+
cleaned++;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.logger.log(`WAL recovery: ${reEnqueued} re-enqueued, ${interrupted} interrupted, ${cleaned} cleaned`);
|
|
149
|
+
return { reEnqueued, interrupted, cleaned };
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Returns the messages that should be re-enqueued after recovery.
|
|
153
|
+
* Called by the recovery procedure to get pending messages.
|
|
154
|
+
*/
|
|
155
|
+
async getPendingMessages() {
|
|
156
|
+
const indexKey = this.walIndexKey();
|
|
157
|
+
const members = await this.redis.zrange(indexKey, 0, -1);
|
|
158
|
+
const pending = [];
|
|
159
|
+
for (const member of members) {
|
|
160
|
+
const parts = member.split(':');
|
|
161
|
+
const messageId = parts[parts.length - 1];
|
|
162
|
+
const entityKey = parts.slice(0, -1).join(':');
|
|
163
|
+
const entry = await this.getEntry(entityKey, messageId);
|
|
164
|
+
if (entry && entry.state === 'enqueued') {
|
|
165
|
+
pending.push(entry.message);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return pending;
|
|
169
|
+
}
|
|
170
|
+
// =========================================================================
|
|
171
|
+
// DEAD LETTER
|
|
172
|
+
// =========================================================================
|
|
173
|
+
onDeadLetter(callback) {
|
|
174
|
+
this.deadLetterCallbacks.push(callback);
|
|
175
|
+
}
|
|
176
|
+
async deadLetter(entityType, message, reason) {
|
|
177
|
+
const deadKey = this.deadLetterKey(entityType);
|
|
178
|
+
await this.redis.lpush(deadKey, JSON.stringify({
|
|
179
|
+
...message,
|
|
180
|
+
deadLetteredAt: Date.now(),
|
|
181
|
+
deadLetterReason: reason,
|
|
182
|
+
}));
|
|
183
|
+
this.logger.warn(`Dead-lettered ${message.name} for ${entityType}:${message.entityId}: ${reason}`);
|
|
184
|
+
for (const cb of this.deadLetterCallbacks) {
|
|
185
|
+
try {
|
|
186
|
+
cb(entityType, message, reason);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
/* subscriber errors don't propagate */
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async getDeadLetters(entityType, limit = 100) {
|
|
194
|
+
const deadKey = this.deadLetterKey(entityType);
|
|
195
|
+
const raw = await this.redis.lrange(deadKey, 0, limit - 1);
|
|
196
|
+
return raw.map((r) => JSON.parse(r));
|
|
197
|
+
}
|
|
198
|
+
// =========================================================================
|
|
199
|
+
// CLEANUP
|
|
200
|
+
// =========================================================================
|
|
201
|
+
startCleanup() {
|
|
202
|
+
if (this.cleanupTimer)
|
|
203
|
+
return;
|
|
204
|
+
this.cleanupTimer = setInterval(() => {
|
|
205
|
+
this.cleanup().catch((err) => {
|
|
206
|
+
this.logger.error(`WAL cleanup error: ${err.message}`);
|
|
207
|
+
});
|
|
208
|
+
}, this.cleanupInterval);
|
|
209
|
+
}
|
|
210
|
+
stopCleanup() {
|
|
211
|
+
if (this.cleanupTimer) {
|
|
212
|
+
clearInterval(this.cleanupTimer);
|
|
213
|
+
this.cleanupTimer = null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async cleanup() {
|
|
217
|
+
const indexKey = this.walIndexKey();
|
|
218
|
+
const staleThreshold = Date.now() - this.entryTTL * 1000;
|
|
219
|
+
const members = await this.redis.zrangebyscore(indexKey, 0, staleThreshold);
|
|
220
|
+
if (members.length === 0)
|
|
221
|
+
return;
|
|
222
|
+
let cleaned = 0;
|
|
223
|
+
for (const member of members) {
|
|
224
|
+
const parts = member.split(':');
|
|
225
|
+
const messageId = parts[parts.length - 1];
|
|
226
|
+
const entityKey = parts.slice(0, -1).join(':');
|
|
227
|
+
const entryKey = this.walEntryKey(entityKey, messageId);
|
|
228
|
+
const state = await this.redis.hget(entryKey, 'state');
|
|
229
|
+
if (!state || state === 'completed' || state === 'failed' || state === 'interrupted') {
|
|
230
|
+
const pipeline = this.redis.pipeline();
|
|
231
|
+
pipeline.del(entryKey);
|
|
232
|
+
pipeline.zrem(indexKey, member);
|
|
233
|
+
await pipeline.exec();
|
|
234
|
+
cleaned++;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (cleaned > 0) {
|
|
238
|
+
this.logger.debug(`WAL cleanup: removed ${cleaned} entries`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
exports.WalService = WalService;
|
|
243
|
+
//# sourceMappingURL=wal.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wal.service.js","sourceRoot":"","sources":["../../src/wal/wal.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ISerializedMessage, IWalConfig } from '../domain';
|
|
2
|
+
export type WalState = 'enqueued' | 'dispatched' | 'completed' | 'failed' | 'interrupted';
|
|
3
|
+
export interface IWalEntry {
|
|
4
|
+
messageId: string;
|
|
5
|
+
state: WalState;
|
|
6
|
+
message: ISerializedMessage;
|
|
7
|
+
entityKey: string;
|
|
8
|
+
serverId: string;
|
|
9
|
+
enqueuedAt: number;
|
|
10
|
+
dispatchedAt?: number;
|
|
11
|
+
completedAt?: number;
|
|
12
|
+
error?: string;
|
|
13
|
+
errorStack?: string;
|
|
14
|
+
correlationId?: string;
|
|
15
|
+
workerId?: number;
|
|
16
|
+
}
|
|
17
|
+
export { IWalConfig };
|
|
18
|
+
export interface IWalRecoveryResult {
|
|
19
|
+
reEnqueued: number;
|
|
20
|
+
interrupted: number;
|
|
21
|
+
cleaned: number;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=wal.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wal.types.d.ts","sourceRoot":"","sources":["../../src/wal/wal.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE3D,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,aAAa,CAAC;AAE1F,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wal.types.js","sourceRoot":"","sources":["../../src/wal/wal.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MurmurHash3 (32-bit) — deterministic, fast, excellent distribution.
|
|
3
|
+
* Pure JS implementation, no dependencies.
|
|
4
|
+
*/
|
|
5
|
+
export declare function murmurhash3(key: string, seed?: number): number;
|
|
6
|
+
/**
|
|
7
|
+
* A node on the consistent hash ring.
|
|
8
|
+
*/
|
|
9
|
+
export interface HashRingNode<T = unknown> {
|
|
10
|
+
/** Unique identifier for this node (e.g. workerId, serverId) */
|
|
11
|
+
id: string;
|
|
12
|
+
/** Arbitrary metadata attached to the node */
|
|
13
|
+
data: T;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Consistent hash ring with virtual nodes.
|
|
17
|
+
*
|
|
18
|
+
* Provides O(log n) lookups and minimizes entity reassignment
|
|
19
|
+
* when nodes are added or removed (~1/N entities move).
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const ring = new ConsistentHashRing<number>(150);
|
|
24
|
+
* ring.addNode({ id: 'worker-0', data: 0 });
|
|
25
|
+
* ring.addNode({ id: 'worker-1', data: 1 });
|
|
26
|
+
*
|
|
27
|
+
* const owner = ring.getNode('account:a-123');
|
|
28
|
+
* // owner.data === 0 or 1 (deterministic for same key)
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class ConsistentHashRing<T = unknown> {
|
|
32
|
+
private ring;
|
|
33
|
+
private readonly nodes;
|
|
34
|
+
private readonly virtualNodesPerNode;
|
|
35
|
+
constructor(virtualNodesPerNode?: number);
|
|
36
|
+
/**
|
|
37
|
+
* Add a node to the ring with its virtual nodes.
|
|
38
|
+
* If a node with this ID already exists, it is replaced.
|
|
39
|
+
*/
|
|
40
|
+
addNode(node: HashRingNode<T>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Remove a node and all its virtual nodes from the ring.
|
|
43
|
+
*/
|
|
44
|
+
removeNode(nodeId: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Get the node that owns the given key.
|
|
47
|
+
* Returns null if the ring is empty.
|
|
48
|
+
*
|
|
49
|
+
* Uses binary search to find the first virtual node
|
|
50
|
+
* whose hash is >= the key's hash (clockwise walk).
|
|
51
|
+
*/
|
|
52
|
+
getNode(key: string): HashRingNode<T> | null;
|
|
53
|
+
/**
|
|
54
|
+
* Get the node that owns the given key, but only consider nodes
|
|
55
|
+
* that pass the filter. Walks clockwise until a matching node is found.
|
|
56
|
+
*
|
|
57
|
+
* Useful for entity-type affinity: skip nodes that don't handle
|
|
58
|
+
* the entity type.
|
|
59
|
+
*
|
|
60
|
+
* Returns null if no matching node exists.
|
|
61
|
+
*/
|
|
62
|
+
getNodeFiltered(key: string, filter: (node: HashRingNode<T>) => boolean): HashRingNode<T> | null;
|
|
63
|
+
/**
|
|
64
|
+
* Check if a specific node owns the given key.
|
|
65
|
+
*/
|
|
66
|
+
isOwner(nodeId: string, key: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Get all node IDs currently in the ring.
|
|
69
|
+
*/
|
|
70
|
+
getNodeIds(): string[];
|
|
71
|
+
/**
|
|
72
|
+
* Get the number of physical nodes in the ring.
|
|
73
|
+
*/
|
|
74
|
+
get size(): number;
|
|
75
|
+
/**
|
|
76
|
+
* Check if a node exists in the ring.
|
|
77
|
+
*/
|
|
78
|
+
hasNode(nodeId: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Get a node by its ID.
|
|
81
|
+
*/
|
|
82
|
+
getNodeById(nodeId: string): HashRingNode<T> | null;
|
|
83
|
+
/**
|
|
84
|
+
* Compute which keys from the given set would be reassigned
|
|
85
|
+
* if a node were added or removed.
|
|
86
|
+
*
|
|
87
|
+
* Returns a map of key → new owner node ID.
|
|
88
|
+
*/
|
|
89
|
+
computeReassignment(keys: Iterable<string>, operation: {
|
|
90
|
+
type: 'add';
|
|
91
|
+
node: HashRingNode<T>;
|
|
92
|
+
} | {
|
|
93
|
+
type: 'remove';
|
|
94
|
+
nodeId: string;
|
|
95
|
+
}): Map<string, string>;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=consistent-hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consistent-hash.d.ts","sourceRoot":"","sources":["../../src/workers/consistent-hash.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,MAAM,CAiDzD;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,8CAA8C;IAC9C,IAAI,EAAE,CAAC,CAAC;CACT;AAQD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,kBAAkB,CAAC,CAAC,GAAG,OAAO;IACzC,OAAO,CAAC,IAAI,CAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsC;IAC5D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;gBAEjC,mBAAmB,SAAM;IAIrC;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAmBpC;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAKhC;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAyB5C;;;;;;;;OAQG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAoChG;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAK7C;;OAEG;IACH,UAAU,IAAI,MAAM,EAAE;IAItB;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIhC;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAInD;;;;;OAKG;IACH,mBAAmB,CACjB,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EACtB,SAAS,EAAE;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GACrF,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;CA0BvB"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConsistentHashRing = void 0;
|
|
4
|
+
exports.murmurhash3 = murmurhash3;
|
|
5
|
+
/**
|
|
6
|
+
* MurmurHash3 (32-bit) — deterministic, fast, excellent distribution.
|
|
7
|
+
* Pure JS implementation, no dependencies.
|
|
8
|
+
*/
|
|
9
|
+
function murmurhash3(key, seed = 0) {
|
|
10
|
+
let h1 = seed >>> 0;
|
|
11
|
+
const len = key.length;
|
|
12
|
+
const nblocks = len >> 2;
|
|
13
|
+
const c1 = 0xcc9e2d51;
|
|
14
|
+
const c2 = 0x1b873593;
|
|
15
|
+
// Body
|
|
16
|
+
for (let i = 0; i < nblocks; i++) {
|
|
17
|
+
let k1 = (key.charCodeAt(i * 4) & 0xff) |
|
|
18
|
+
((key.charCodeAt(i * 4 + 1) & 0xff) << 8) |
|
|
19
|
+
((key.charCodeAt(i * 4 + 2) & 0xff) << 16) |
|
|
20
|
+
((key.charCodeAt(i * 4 + 3) & 0xff) << 24);
|
|
21
|
+
k1 = Math.imul(k1, c1);
|
|
22
|
+
k1 = (k1 << 15) | (k1 >>> 17);
|
|
23
|
+
k1 = Math.imul(k1, c2);
|
|
24
|
+
h1 ^= k1;
|
|
25
|
+
h1 = (h1 << 13) | (h1 >>> 19);
|
|
26
|
+
h1 = Math.imul(h1, 5) + 0xe6546b64;
|
|
27
|
+
}
|
|
28
|
+
// Tail
|
|
29
|
+
const tail = nblocks * 4;
|
|
30
|
+
let k1 = 0;
|
|
31
|
+
const remainder = len & 3;
|
|
32
|
+
if (remainder >= 3)
|
|
33
|
+
k1 ^= (key.charCodeAt(tail + 2) & 0xff) << 16;
|
|
34
|
+
if (remainder >= 2)
|
|
35
|
+
k1 ^= (key.charCodeAt(tail + 1) & 0xff) << 8;
|
|
36
|
+
if (remainder >= 1) {
|
|
37
|
+
k1 ^= key.charCodeAt(tail) & 0xff;
|
|
38
|
+
k1 = Math.imul(k1, c1);
|
|
39
|
+
k1 = (k1 << 15) | (k1 >>> 17);
|
|
40
|
+
k1 = Math.imul(k1, c2);
|
|
41
|
+
h1 ^= k1;
|
|
42
|
+
}
|
|
43
|
+
// Finalization
|
|
44
|
+
h1 ^= len;
|
|
45
|
+
h1 ^= h1 >>> 16;
|
|
46
|
+
h1 = Math.imul(h1, 0x85ebca6b);
|
|
47
|
+
h1 ^= h1 >>> 13;
|
|
48
|
+
h1 = Math.imul(h1, 0xc2b2ae35);
|
|
49
|
+
h1 ^= h1 >>> 16;
|
|
50
|
+
return h1 >>> 0;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Consistent hash ring with virtual nodes.
|
|
54
|
+
*
|
|
55
|
+
* Provides O(log n) lookups and minimizes entity reassignment
|
|
56
|
+
* when nodes are added or removed (~1/N entities move).
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const ring = new ConsistentHashRing<number>(150);
|
|
61
|
+
* ring.addNode({ id: 'worker-0', data: 0 });
|
|
62
|
+
* ring.addNode({ id: 'worker-1', data: 1 });
|
|
63
|
+
*
|
|
64
|
+
* const owner = ring.getNode('account:a-123');
|
|
65
|
+
* // owner.data === 0 or 1 (deterministic for same key)
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
class ConsistentHashRing {
|
|
69
|
+
constructor(virtualNodesPerNode = 150) {
|
|
70
|
+
this.ring = [];
|
|
71
|
+
this.nodes = new Map();
|
|
72
|
+
this.virtualNodesPerNode = virtualNodesPerNode;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Add a node to the ring with its virtual nodes.
|
|
76
|
+
* If a node with this ID already exists, it is replaced.
|
|
77
|
+
*/
|
|
78
|
+
addNode(node) {
|
|
79
|
+
if (this.nodes.has(node.id)) {
|
|
80
|
+
this.removeNode(node.id);
|
|
81
|
+
}
|
|
82
|
+
this.nodes.set(node.id, node);
|
|
83
|
+
for (let i = 0; i < this.virtualNodesPerNode; i++) {
|
|
84
|
+
const key = `${node.id}:vnode:${i}`;
|
|
85
|
+
this.ring.push({
|
|
86
|
+
hash: murmurhash3(key),
|
|
87
|
+
nodeId: node.id,
|
|
88
|
+
data: node.data,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
this.ring.sort((a, b) => a.hash - b.hash);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Remove a node and all its virtual nodes from the ring.
|
|
95
|
+
*/
|
|
96
|
+
removeNode(nodeId) {
|
|
97
|
+
this.nodes.delete(nodeId);
|
|
98
|
+
this.ring = this.ring.filter((vn) => vn.nodeId !== nodeId);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get the node that owns the given key.
|
|
102
|
+
* Returns null if the ring is empty.
|
|
103
|
+
*
|
|
104
|
+
* Uses binary search to find the first virtual node
|
|
105
|
+
* whose hash is >= the key's hash (clockwise walk).
|
|
106
|
+
*/
|
|
107
|
+
getNode(key) {
|
|
108
|
+
if (this.ring.length === 0)
|
|
109
|
+
return null;
|
|
110
|
+
const hash = murmurhash3(key);
|
|
111
|
+
// Binary search for first virtual node with hash >= key hash
|
|
112
|
+
let lo = 0;
|
|
113
|
+
let hi = this.ring.length;
|
|
114
|
+
while (lo < hi) {
|
|
115
|
+
const mid = (lo + hi) >>> 1;
|
|
116
|
+
if (this.ring[mid].hash < hash) {
|
|
117
|
+
lo = mid + 1;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
hi = mid;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Wrap around to the first node if we're past the end
|
|
124
|
+
const idx = lo < this.ring.length ? lo : 0;
|
|
125
|
+
const vnode = this.ring[idx];
|
|
126
|
+
return this.nodes.get(vnode.nodeId) ?? null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get the node that owns the given key, but only consider nodes
|
|
130
|
+
* that pass the filter. Walks clockwise until a matching node is found.
|
|
131
|
+
*
|
|
132
|
+
* Useful for entity-type affinity: skip nodes that don't handle
|
|
133
|
+
* the entity type.
|
|
134
|
+
*
|
|
135
|
+
* Returns null if no matching node exists.
|
|
136
|
+
*/
|
|
137
|
+
getNodeFiltered(key, filter) {
|
|
138
|
+
if (this.ring.length === 0)
|
|
139
|
+
return null;
|
|
140
|
+
const hash = murmurhash3(key);
|
|
141
|
+
// Find starting position
|
|
142
|
+
let lo = 0;
|
|
143
|
+
let hi = this.ring.length;
|
|
144
|
+
while (lo < hi) {
|
|
145
|
+
const mid = (lo + hi) >>> 1;
|
|
146
|
+
if (this.ring[mid].hash < hash) {
|
|
147
|
+
lo = mid + 1;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
hi = mid;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Walk clockwise, checking filter
|
|
154
|
+
const visited = new Set();
|
|
155
|
+
for (let i = 0; i < this.ring.length; i++) {
|
|
156
|
+
const idx = (lo + i) % this.ring.length;
|
|
157
|
+
const vnode = this.ring[idx];
|
|
158
|
+
if (visited.has(vnode.nodeId))
|
|
159
|
+
continue;
|
|
160
|
+
visited.add(vnode.nodeId);
|
|
161
|
+
const node = this.nodes.get(vnode.nodeId);
|
|
162
|
+
if (node && filter(node))
|
|
163
|
+
return node;
|
|
164
|
+
// If we've checked all distinct nodes, stop
|
|
165
|
+
if (visited.size >= this.nodes.size)
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Check if a specific node owns the given key.
|
|
172
|
+
*/
|
|
173
|
+
isOwner(nodeId, key) {
|
|
174
|
+
const owner = this.getNode(key);
|
|
175
|
+
return owner?.id === nodeId;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get all node IDs currently in the ring.
|
|
179
|
+
*/
|
|
180
|
+
getNodeIds() {
|
|
181
|
+
return Array.from(this.nodes.keys());
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get the number of physical nodes in the ring.
|
|
185
|
+
*/
|
|
186
|
+
get size() {
|
|
187
|
+
return this.nodes.size;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Check if a node exists in the ring.
|
|
191
|
+
*/
|
|
192
|
+
hasNode(nodeId) {
|
|
193
|
+
return this.nodes.has(nodeId);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get a node by its ID.
|
|
197
|
+
*/
|
|
198
|
+
getNodeById(nodeId) {
|
|
199
|
+
return this.nodes.get(nodeId) ?? null;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Compute which keys from the given set would be reassigned
|
|
203
|
+
* if a node were added or removed.
|
|
204
|
+
*
|
|
205
|
+
* Returns a map of key → new owner node ID.
|
|
206
|
+
*/
|
|
207
|
+
computeReassignment(keys, operation) {
|
|
208
|
+
// Create a hypothetical ring with the change applied
|
|
209
|
+
const hypothetical = new ConsistentHashRing(this.virtualNodesPerNode);
|
|
210
|
+
for (const [id, node] of this.nodes) {
|
|
211
|
+
if (operation.type === 'remove' && id === operation.nodeId)
|
|
212
|
+
continue;
|
|
213
|
+
hypothetical.addNode(node);
|
|
214
|
+
}
|
|
215
|
+
if (operation.type === 'add') {
|
|
216
|
+
hypothetical.addNode(operation.node);
|
|
217
|
+
}
|
|
218
|
+
// Find keys that changed ownership
|
|
219
|
+
const reassignment = new Map();
|
|
220
|
+
for (const key of keys) {
|
|
221
|
+
const currentOwner = this.getNode(key);
|
|
222
|
+
const newOwner = hypothetical.getNode(key);
|
|
223
|
+
if (currentOwner?.id !== newOwner?.id && newOwner) {
|
|
224
|
+
reassignment.set(key, newOwner.id);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return reassignment;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
exports.ConsistentHashRing = ConsistentHashRing;
|
|
231
|
+
//# sourceMappingURL=consistent-hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consistent-hash.js","sourceRoot":"","sources":["../../src/workers/consistent-hash.ts"],"names":[],"mappings":"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"}
|