@zdavison/matador 2.0.10 → 2.0.12
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/dist/core/matador.d.ts +14 -1
- package/dist/core/matador.d.ts.map +1 -1
- package/dist/core/matador.js +20 -2
- package/dist/core/matador.test.js +100 -0
- package/dist/core/shutdown.d.ts +12 -1
- package/dist/core/shutdown.d.ts.map +1 -1
- package/dist/core/shutdown.js +26 -4
- package/dist/core/shutdown.test.js +75 -0
- package/dist/index.cjs +44 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/matador.d.ts
CHANGED
|
@@ -120,6 +120,19 @@ export declare class Matador implements Dispatcher {
|
|
|
120
120
|
* Waits for all handlers to become idle.
|
|
121
121
|
*/
|
|
122
122
|
waitForIdle(timeoutMs?: number): Promise<boolean>;
|
|
123
|
+
/**
|
|
124
|
+
* Stops receiving new messages without performing full shutdown.
|
|
125
|
+
* After calling this, no new messages will be delivered from RabbitMQ.
|
|
126
|
+
* The transport remains connected for later shutdown.
|
|
127
|
+
*
|
|
128
|
+
* Use this when you need to coordinate shutdown across multiple systems:
|
|
129
|
+
* 1. Call stopReceiving() to stop new message delivery
|
|
130
|
+
* 2. Wait for both Matador and your other systems to idle
|
|
131
|
+
* 3. Call shutdown() to disconnect (or let NestJS lifecycle handle it)
|
|
132
|
+
*
|
|
133
|
+
* @returns true if receiving was stopped, false if not started or already stopped
|
|
134
|
+
*/
|
|
135
|
+
stopReceiving(): Promise<boolean>;
|
|
123
136
|
/**
|
|
124
137
|
* Gracefully shuts down Matador.
|
|
125
138
|
*/
|
|
@@ -128,6 +141,6 @@ export declare class Matador implements Dispatcher {
|
|
|
128
141
|
* Checks if transport is connected.
|
|
129
142
|
*/
|
|
130
143
|
isConnected(): boolean;
|
|
131
|
-
private
|
|
144
|
+
private unsubscribeAll;
|
|
132
145
|
}
|
|
133
146
|
//# sourceMappingURL=matador.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matador.d.ts","sourceRoot":"","sources":["../../src/core/matador.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"matador.d.ts","sourceRoot":"","sources":["../../src/core/matador.ts"],"names":[],"mappings":"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"}
|
package/dist/core/matador.js
CHANGED
|
@@ -68,7 +68,7 @@ export class Matador {
|
|
|
68
68
|
defaultQueue,
|
|
69
69
|
});
|
|
70
70
|
// Create shutdown manager
|
|
71
|
-
this.shutdownManager = new ShutdownManager(() => this.fanout.eventsBeingEnqueuedCount, () => this.
|
|
71
|
+
this.shutdownManager = new ShutdownManager(() => this.fanout.eventsBeingEnqueuedCount, () => this.unsubscribeAll(), () => this.transport.disconnect(), config.shutdownConfig);
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
74
74
|
* Registers an event class with its subscribers.
|
|
@@ -203,6 +203,24 @@ export class Matador {
|
|
|
203
203
|
}
|
|
204
204
|
return true;
|
|
205
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* Stops receiving new messages without performing full shutdown.
|
|
208
|
+
* After calling this, no new messages will be delivered from RabbitMQ.
|
|
209
|
+
* The transport remains connected for later shutdown.
|
|
210
|
+
*
|
|
211
|
+
* Use this when you need to coordinate shutdown across multiple systems:
|
|
212
|
+
* 1. Call stopReceiving() to stop new message delivery
|
|
213
|
+
* 2. Wait for both Matador and your other systems to idle
|
|
214
|
+
* 3. Call shutdown() to disconnect (or let NestJS lifecycle handle it)
|
|
215
|
+
*
|
|
216
|
+
* @returns true if receiving was stopped, false if not started or already stopped
|
|
217
|
+
*/
|
|
218
|
+
async stopReceiving() {
|
|
219
|
+
if (!this.started) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return this.shutdownManager.publicStopReceiving();
|
|
223
|
+
}
|
|
206
224
|
/**
|
|
207
225
|
* Gracefully shuts down Matador.
|
|
208
226
|
*/
|
|
@@ -219,7 +237,7 @@ export class Matador {
|
|
|
219
237
|
isConnected() {
|
|
220
238
|
return this.transport.isConnected();
|
|
221
239
|
}
|
|
222
|
-
async
|
|
240
|
+
async unsubscribeAll() {
|
|
223
241
|
for (const subscription of this.subscriptions) {
|
|
224
242
|
await subscription.unsubscribe();
|
|
225
243
|
}
|
|
@@ -361,6 +361,106 @@ describe('Matador', () => {
|
|
|
361
361
|
expect(matador.send(event)).rejects.toThrow();
|
|
362
362
|
});
|
|
363
363
|
});
|
|
364
|
+
describe('stopReceiving', () => {
|
|
365
|
+
it('should return false when not started', async () => {
|
|
366
|
+
const topology = TopologyBuilder.create()
|
|
367
|
+
.withNamespace('test')
|
|
368
|
+
.addQueue('events')
|
|
369
|
+
.build();
|
|
370
|
+
const subscriber = createSubscriber({
|
|
371
|
+
name: 'handle-user',
|
|
372
|
+
description: 'Handles user events',
|
|
373
|
+
callback: async () => { },
|
|
374
|
+
});
|
|
375
|
+
const schema = {
|
|
376
|
+
[UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
|
|
377
|
+
};
|
|
378
|
+
matador = new Matador({ transport, topology, schema });
|
|
379
|
+
const result = await matador.stopReceiving();
|
|
380
|
+
expect(result).toBe(false);
|
|
381
|
+
});
|
|
382
|
+
it('should return true when started and stop receiving messages', async () => {
|
|
383
|
+
const topology = TopologyBuilder.create()
|
|
384
|
+
.withNamespace('test')
|
|
385
|
+
.addQueue('events')
|
|
386
|
+
.build();
|
|
387
|
+
const subscriber = createSubscriber({
|
|
388
|
+
name: 'handle-user',
|
|
389
|
+
description: 'Handles user events',
|
|
390
|
+
callback: async () => { },
|
|
391
|
+
});
|
|
392
|
+
const schema = {
|
|
393
|
+
[UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
|
|
394
|
+
};
|
|
395
|
+
matador = new Matador({ transport, topology, schema });
|
|
396
|
+
await matador.start();
|
|
397
|
+
const result = await matador.stopReceiving();
|
|
398
|
+
expect(result).toBe(true);
|
|
399
|
+
expect(matador.isConnected()).toBe(true);
|
|
400
|
+
});
|
|
401
|
+
it('should return false when called twice', async () => {
|
|
402
|
+
const topology = TopologyBuilder.create()
|
|
403
|
+
.withNamespace('test')
|
|
404
|
+
.addQueue('events')
|
|
405
|
+
.build();
|
|
406
|
+
const subscriber = createSubscriber({
|
|
407
|
+
name: 'handle-user',
|
|
408
|
+
description: 'Handles user events',
|
|
409
|
+
callback: async () => { },
|
|
410
|
+
});
|
|
411
|
+
const schema = {
|
|
412
|
+
[UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
|
|
413
|
+
};
|
|
414
|
+
matador = new Matador({ transport, topology, schema });
|
|
415
|
+
await matador.start();
|
|
416
|
+
const result1 = await matador.stopReceiving();
|
|
417
|
+
const result2 = await matador.stopReceiving();
|
|
418
|
+
expect(result1).toBe(true);
|
|
419
|
+
expect(result2).toBe(false);
|
|
420
|
+
});
|
|
421
|
+
it('should allow shutdown after stopReceiving', async () => {
|
|
422
|
+
const topology = TopologyBuilder.create()
|
|
423
|
+
.withNamespace('test')
|
|
424
|
+
.addQueue('events')
|
|
425
|
+
.build();
|
|
426
|
+
const subscriber = createSubscriber({
|
|
427
|
+
name: 'handle-user',
|
|
428
|
+
description: 'Handles user events',
|
|
429
|
+
callback: async () => { },
|
|
430
|
+
});
|
|
431
|
+
const schema = {
|
|
432
|
+
[UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
|
|
433
|
+
};
|
|
434
|
+
matador = new Matador({ transport, topology, schema });
|
|
435
|
+
await matador.start();
|
|
436
|
+
await matador.stopReceiving();
|
|
437
|
+
await matador.shutdown();
|
|
438
|
+
expect(matador.isConnected()).toBe(false);
|
|
439
|
+
});
|
|
440
|
+
it('should allow sending events after stopReceiving but before shutdown', async () => {
|
|
441
|
+
const topology = TopologyBuilder.create()
|
|
442
|
+
.withNamespace('test')
|
|
443
|
+
.addQueue('events')
|
|
444
|
+
.build();
|
|
445
|
+
const subscriber = createSubscriber({
|
|
446
|
+
name: 'handle-user',
|
|
447
|
+
description: 'Handles user events',
|
|
448
|
+
callback: async () => { },
|
|
449
|
+
});
|
|
450
|
+
const schema = {
|
|
451
|
+
[UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
|
|
452
|
+
};
|
|
453
|
+
matador = new Matador({ transport, topology, schema });
|
|
454
|
+
await matador.start();
|
|
455
|
+
await matador.stopReceiving();
|
|
456
|
+
const event = new UserCreatedEvent({
|
|
457
|
+
userId: '123',
|
|
458
|
+
email: 'test@example.com',
|
|
459
|
+
});
|
|
460
|
+
const result = await matador.send(event);
|
|
461
|
+
expect(result.subscribersSent).toBe(1);
|
|
462
|
+
});
|
|
463
|
+
});
|
|
364
464
|
describe('idle state', () => {
|
|
365
465
|
it('should report idle when no processing', async () => {
|
|
366
466
|
const topology = TopologyBuilder.create()
|
package/dist/core/shutdown.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type Logger } from '../hooks/index.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Shutdown state.
|
|
4
4
|
*/
|
|
5
|
-
export type ShutdownState = 'running' | 'stopping-receive' | 'waiting-handlers' | 'stopping-enqueue' | 'disconnecting' | 'stopped';
|
|
5
|
+
export type ShutdownState = 'running' | 'receive-stopped' | 'stopping-receive' | 'waiting-handlers' | 'stopping-enqueue' | 'disconnecting' | 'stopped';
|
|
6
6
|
/**
|
|
7
7
|
* Configuration for shutdown manager.
|
|
8
8
|
*/
|
|
@@ -64,6 +64,17 @@ export declare class ShutdownManager {
|
|
|
64
64
|
* Decrement processing counter.
|
|
65
65
|
*/
|
|
66
66
|
decrementProcessing(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Stops receiving new messages without performing full shutdown.
|
|
69
|
+
* After calling this, no new messages will be delivered from the transport.
|
|
70
|
+
* The transport remains connected for later shutdown.
|
|
71
|
+
*
|
|
72
|
+
* Use this when you need to stop receiving before waiting for idle,
|
|
73
|
+
* for example to coordinate waiting across multiple systems.
|
|
74
|
+
*
|
|
75
|
+
* @returns true if receiving was stopped, false if already stopped or shutting down
|
|
76
|
+
*/
|
|
77
|
+
publicStopReceiving(): Promise<boolean>;
|
|
67
78
|
/**
|
|
68
79
|
* Performs graceful shutdown.
|
|
69
80
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/core/shutdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAiB,MAAM,mBAAmB,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,kBAAkB,GAClB,kBAAkB,GAClB,kBAAkB,GAClB,eAAe,GACf,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;IAEzC,yDAAyD;IACzD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IAErC,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,cAInC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAOxB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IARtC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,gBAAgB,CAAQ;gBAGb,eAAe,EAAE,MAAM,MAAM,EAC7B,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAClC,mBAAmB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACzD,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM;IAKtC;;OAEG;IACH,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED;;OAEG;IACH,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED;;OAEG;IACH,gBAAgB,IAAI,aAAa;IASjC;;OAEG;IACH,mBAAmB,IAAI,IAAI;IAI3B;;OAEG;IACH,mBAAmB,IAAI,IAAI;IAI3B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/core/shutdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAiB,MAAM,mBAAmB,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,iBAAiB,GACjB,kBAAkB,GAClB,kBAAkB,GAClB,kBAAkB,GAClB,eAAe,GACf,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;IAEzC,yDAAyD;IACzD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IAErC,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,cAInC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAOxB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IARtC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,gBAAgB,CAAQ;gBAGb,eAAe,EAAE,MAAM,MAAM,EAC7B,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAClC,mBAAmB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACzD,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM;IAKtC;;OAEG;IACH,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED;;OAEG;IACH,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED;;OAEG;IACH,gBAAgB,IAAI,aAAa;IASjC;;OAEG;IACH,mBAAmB,IAAI,IAAI;IAI3B;;OAEG;IACH,mBAAmB,IAAI,IAAI;IAI3B;;;;;;;;;OASG;IACG,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAW7C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B/B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;YAOlB,WAAW;IAezB,OAAO,CAAC,KAAK;CAGd"}
|
package/dist/core/shutdown.js
CHANGED
|
@@ -66,15 +66,37 @@ export class ShutdownManager {
|
|
|
66
66
|
this.eventsBeingProcessed--;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
69
|
+
* Stops receiving new messages without performing full shutdown.
|
|
70
|
+
* After calling this, no new messages will be delivered from the transport.
|
|
71
|
+
* The transport remains connected for later shutdown.
|
|
72
|
+
*
|
|
73
|
+
* Use this when you need to stop receiving before waiting for idle,
|
|
74
|
+
* for example to coordinate waiting across multiple systems.
|
|
75
|
+
*
|
|
76
|
+
* @returns true if receiving was stopped, false if already stopped or shutting down
|
|
70
77
|
*/
|
|
71
|
-
async
|
|
78
|
+
async publicStopReceiving() {
|
|
72
79
|
if (this._state !== 'running') {
|
|
73
|
-
return;
|
|
80
|
+
return false;
|
|
74
81
|
}
|
|
75
|
-
// 1. Stop receiving new messages
|
|
76
82
|
this._state = 'stopping-receive';
|
|
77
83
|
await this.stopReceiving();
|
|
84
|
+
this._state = 'receive-stopped';
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Performs graceful shutdown.
|
|
89
|
+
*/
|
|
90
|
+
async shutdown() {
|
|
91
|
+
// Allow shutdown from either 'running' or 'receive-stopped' states
|
|
92
|
+
if (this._state !== 'running' && this._state !== 'receive-stopped') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// 1. Stop receiving new messages (skip if already stopped)
|
|
96
|
+
if (this._state === 'running') {
|
|
97
|
+
this._state = 'stopping-receive';
|
|
98
|
+
await this.stopReceiving();
|
|
99
|
+
}
|
|
78
100
|
// 2. Wait for handlers to idle
|
|
79
101
|
this._state = 'waiting-handlers';
|
|
80
102
|
await this.waitForIdle();
|
|
@@ -278,6 +278,81 @@ describe('ShutdownManager', () => {
|
|
|
278
278
|
expect(stopReceiving).toHaveBeenCalledTimes(1);
|
|
279
279
|
});
|
|
280
280
|
});
|
|
281
|
+
describe('publicStopReceiving', () => {
|
|
282
|
+
beforeEach(() => {
|
|
283
|
+
manager = new ShutdownManager(getEnqueueCount, stopReceiving, disconnectTransport);
|
|
284
|
+
});
|
|
285
|
+
it('should return true when called from running state', async () => {
|
|
286
|
+
const result = await manager.publicStopReceiving();
|
|
287
|
+
expect(result).toBe(true);
|
|
288
|
+
});
|
|
289
|
+
it('should transition to receive-stopped state', async () => {
|
|
290
|
+
await manager.publicStopReceiving();
|
|
291
|
+
expect(manager.state).toBe('receive-stopped');
|
|
292
|
+
});
|
|
293
|
+
it('should call stopReceiving callback', async () => {
|
|
294
|
+
await manager.publicStopReceiving();
|
|
295
|
+
expect(stopReceiving).toHaveBeenCalledTimes(1);
|
|
296
|
+
});
|
|
297
|
+
it('should return false when called after already stopped receiving', async () => {
|
|
298
|
+
await manager.publicStopReceiving();
|
|
299
|
+
const result = await manager.publicStopReceiving();
|
|
300
|
+
expect(result).toBe(false);
|
|
301
|
+
expect(stopReceiving).toHaveBeenCalledTimes(1);
|
|
302
|
+
});
|
|
303
|
+
it('should return false when called after shutdown started', async () => {
|
|
304
|
+
manager.incrementProcessing();
|
|
305
|
+
const shutdownPromise = manager.shutdown();
|
|
306
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
307
|
+
const result = await manager.publicStopReceiving();
|
|
308
|
+
expect(result).toBe(false);
|
|
309
|
+
manager.decrementProcessing();
|
|
310
|
+
await shutdownPromise;
|
|
311
|
+
});
|
|
312
|
+
it('should still allow enqueue after stopReceiving', async () => {
|
|
313
|
+
await manager.publicStopReceiving();
|
|
314
|
+
expect(manager.isEnqueueAllowed).toBe(true);
|
|
315
|
+
});
|
|
316
|
+
it('should allow shutdown to complete after publicStopReceiving', async () => {
|
|
317
|
+
await manager.publicStopReceiving();
|
|
318
|
+
await manager.shutdown();
|
|
319
|
+
expect(manager.state).toBe('stopped');
|
|
320
|
+
expect(stopReceiving).toHaveBeenCalledTimes(1);
|
|
321
|
+
expect(disconnectTransport).toHaveBeenCalledTimes(1);
|
|
322
|
+
});
|
|
323
|
+
it('should skip stopReceiving during shutdown if already called', async () => {
|
|
324
|
+
await manager.publicStopReceiving();
|
|
325
|
+
expect(stopReceiving).toHaveBeenCalledTimes(1);
|
|
326
|
+
await manager.shutdown();
|
|
327
|
+
expect(stopReceiving).toHaveBeenCalledTimes(1);
|
|
328
|
+
});
|
|
329
|
+
it('should allow waiting for idle after stopReceiving', async () => {
|
|
330
|
+
manager.incrementProcessing();
|
|
331
|
+
await manager.publicStopReceiving();
|
|
332
|
+
expect(manager.state).toBe('receive-stopped');
|
|
333
|
+
expect(manager.getHandlersState().isIdle).toBe(false);
|
|
334
|
+
manager.decrementProcessing();
|
|
335
|
+
expect(manager.getHandlersState().isIdle).toBe(true);
|
|
336
|
+
});
|
|
337
|
+
it('should transition through correct states when shutdown follows publicStopReceiving', async () => {
|
|
338
|
+
const states = [];
|
|
339
|
+
disconnectTransport = mock(async () => {
|
|
340
|
+
states.push(manager.state);
|
|
341
|
+
});
|
|
342
|
+
manager = new ShutdownManager(getEnqueueCount, stopReceiving, disconnectTransport);
|
|
343
|
+
states.push(manager.state);
|
|
344
|
+
await manager.publicStopReceiving();
|
|
345
|
+
states.push(manager.state);
|
|
346
|
+
await manager.shutdown();
|
|
347
|
+
states.push(manager.state);
|
|
348
|
+
expect(states).toEqual([
|
|
349
|
+
'running',
|
|
350
|
+
'receive-stopped',
|
|
351
|
+
'disconnecting',
|
|
352
|
+
'stopped',
|
|
353
|
+
]);
|
|
354
|
+
});
|
|
355
|
+
});
|
|
281
356
|
describe('forceStop', () => {
|
|
282
357
|
beforeEach(() => {
|
|
283
358
|
manager = new ShutdownManager(getEnqueueCount, stopReceiving, disconnectTransport);
|
package/dist/index.cjs
CHANGED
|
@@ -942,14 +942,35 @@ var ShutdownManager = class {
|
|
|
942
942
|
this.eventsBeingProcessed--;
|
|
943
943
|
}
|
|
944
944
|
/**
|
|
945
|
-
*
|
|
945
|
+
* Stops receiving new messages without performing full shutdown.
|
|
946
|
+
* After calling this, no new messages will be delivered from the transport.
|
|
947
|
+
* The transport remains connected for later shutdown.
|
|
948
|
+
*
|
|
949
|
+
* Use this when you need to stop receiving before waiting for idle,
|
|
950
|
+
* for example to coordinate waiting across multiple systems.
|
|
951
|
+
*
|
|
952
|
+
* @returns true if receiving was stopped, false if already stopped or shutting down
|
|
946
953
|
*/
|
|
947
|
-
async
|
|
954
|
+
async publicStopReceiving() {
|
|
948
955
|
if (this._state !== "running") {
|
|
949
|
-
return;
|
|
956
|
+
return false;
|
|
950
957
|
}
|
|
951
958
|
this._state = "stopping-receive";
|
|
952
959
|
await this.stopReceiving();
|
|
960
|
+
this._state = "receive-stopped";
|
|
961
|
+
return true;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Performs graceful shutdown.
|
|
965
|
+
*/
|
|
966
|
+
async shutdown() {
|
|
967
|
+
if (this._state !== "running" && this._state !== "receive-stopped") {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
if (this._state === "running") {
|
|
971
|
+
this._state = "stopping-receive";
|
|
972
|
+
await this.stopReceiving();
|
|
973
|
+
}
|
|
953
974
|
this._state = "waiting-handlers";
|
|
954
975
|
await this.waitForIdle();
|
|
955
976
|
this._state = "stopping-enqueue";
|
|
@@ -1988,7 +2009,7 @@ var Matador = class {
|
|
|
1988
2009
|
});
|
|
1989
2010
|
this.shutdownManager = new ShutdownManager(
|
|
1990
2011
|
() => this.fanout.eventsBeingEnqueuedCount,
|
|
1991
|
-
() => this.
|
|
2012
|
+
() => this.unsubscribeAll(),
|
|
1992
2013
|
() => this.transport.disconnect(),
|
|
1993
2014
|
config.shutdownConfig
|
|
1994
2015
|
);
|
|
@@ -2127,6 +2148,24 @@ var Matador = class {
|
|
|
2127
2148
|
}
|
|
2128
2149
|
return true;
|
|
2129
2150
|
}
|
|
2151
|
+
/**
|
|
2152
|
+
* Stops receiving new messages without performing full shutdown.
|
|
2153
|
+
* After calling this, no new messages will be delivered from RabbitMQ.
|
|
2154
|
+
* The transport remains connected for later shutdown.
|
|
2155
|
+
*
|
|
2156
|
+
* Use this when you need to coordinate shutdown across multiple systems:
|
|
2157
|
+
* 1. Call stopReceiving() to stop new message delivery
|
|
2158
|
+
* 2. Wait for both Matador and your other systems to idle
|
|
2159
|
+
* 3. Call shutdown() to disconnect (or let NestJS lifecycle handle it)
|
|
2160
|
+
*
|
|
2161
|
+
* @returns true if receiving was stopped, false if not started or already stopped
|
|
2162
|
+
*/
|
|
2163
|
+
async stopReceiving() {
|
|
2164
|
+
if (!this.started) {
|
|
2165
|
+
return false;
|
|
2166
|
+
}
|
|
2167
|
+
return this.shutdownManager.publicStopReceiving();
|
|
2168
|
+
}
|
|
2130
2169
|
/**
|
|
2131
2170
|
* Gracefully shuts down Matador.
|
|
2132
2171
|
*/
|
|
@@ -2143,7 +2182,7 @@ var Matador = class {
|
|
|
2143
2182
|
isConnected() {
|
|
2144
2183
|
return this.transport.isConnected();
|
|
2145
2184
|
}
|
|
2146
|
-
async
|
|
2185
|
+
async unsubscribeAll() {
|
|
2147
2186
|
for (const subscription of this.subscriptions) {
|
|
2148
2187
|
await subscription.unsubscribe();
|
|
2149
2188
|
}
|