@bgaldino/nestjs-rabbitmq 2.0.0-beta.4 → 2.0.0-beta.6
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 +99 -105
- package/dist/amqp-connection-manager.d.ts +9 -10
- package/dist/amqp-connection-manager.js +35 -60
- package/dist/amqp-connection-manager.js.map +1 -1
- package/dist/class-discovery.d.ts +1 -0
- package/dist/class-discovery.js +27 -8
- package/dist/class-discovery.js.map +1 -1
- package/dist/connection-factory.d.ts +3 -1
- package/dist/connection-factory.js +8 -0
- package/dist/connection-factory.js.map +1 -1
- package/dist/consumer-activator.service.d.ts +12 -0
- package/dist/consumer-activator.service.js +63 -0
- package/dist/consumer-activator.service.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/rabbitmq-consumer.d.ts +1 -2
- package/dist/rabbitmq-consumer.js +9 -15
- package/dist/rabbitmq-consumer.js.map +1 -1
- package/dist/rabbitmq-retry-handler.d.ts +1 -2
- package/dist/rabbitmq-retry-handler.js +4 -4
- package/dist/rabbitmq-retry-handler.js.map +1 -1
- package/dist/rabbitmq-service.d.ts +1 -2
- package/dist/rabbitmq-service.js +10 -8
- package/dist/rabbitmq-service.js.map +1 -1
- package/dist/rabbitmq.constants.d.ts +1 -0
- package/dist/rabbitmq.constants.js +2 -1
- package/dist/rabbitmq.constants.js.map +1 -1
- package/dist/rabbitmq.interfaces.d.ts +3 -4
- package/dist/rabbitmq.module.d.ts +13 -1
- package/dist/rabbitmq.module.js +32 -6
- package/dist/rabbitmq.module.js.map +1 -1
- package/dist/rabbitmq.types.d.ts +8 -35
- package/dist/rabbitmq.types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,11 +10,12 @@ An opinionated NestJS module for RabbitMQ with built-in retry strategies, dead l
|
|
|
10
10
|
- [forRoot](#forroot)
|
|
11
11
|
- [forRootAsync](#forrootasync)
|
|
12
12
|
- [Consumers](#consumers)
|
|
13
|
+
- [Enabling consumers](#enabling-consumers)
|
|
14
|
+
- [Selective consumer activation](#selective-consumer-activation)
|
|
13
15
|
- [Decorator-based consumers](#decorator-based-consumers)
|
|
14
16
|
- [Config-based consumers](#config-based-consumers)
|
|
15
17
|
- [Mixed usage](#mixed-usage)
|
|
16
18
|
- [Handler signature](#handler-signature)
|
|
17
|
-
- [Consumer groups](#consumer-groups)
|
|
18
19
|
- [Publishers](#publishers)
|
|
19
20
|
- [Publishing messages](#publishing-messages)
|
|
20
21
|
- [Typed publishing](#typed-publishing)
|
|
@@ -27,7 +28,6 @@ An opinionated NestJS module for RabbitMQ with built-in retry strategies, dead l
|
|
|
27
28
|
- [Disabling the automatic ack](#disabling-the-automatic-ack)
|
|
28
29
|
- [Custom Header Metadata](#custom-header-metadata)
|
|
29
30
|
- [Extra Options](#extra-options)
|
|
30
|
-
- [Consumer manual loading](#consumer-manual-loading)
|
|
31
31
|
- [Message inspection and logging](#message-inspection-and-logging)
|
|
32
32
|
- [Health check](#health-check)
|
|
33
33
|
- [Building locally](#building-locally)
|
|
@@ -57,8 +57,13 @@ and dead letter exchanges instead of the delayed message plugin.
|
|
|
57
57
|
|
|
58
58
|
## Getting Started
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
to inject `RabbitMQService` anywhere in your application.
|
|
60
|
+
`RabbitMQModule.forRoot()` is marked as `@Global`, so importing it once is
|
|
61
|
+
enough to inject `RabbitMQService` anywhere in your application. It handles
|
|
62
|
+
connections and publishing.
|
|
63
|
+
|
|
64
|
+
To enable consumers, import `RabbitMQModule.withConsumers()` alongside
|
|
65
|
+
`forRoot()`. Without it, only publisher connections are opened and no messages
|
|
66
|
+
are consumed.
|
|
62
67
|
|
|
63
68
|
### forRoot
|
|
64
69
|
|
|
@@ -71,12 +76,12 @@ import { RabbitMQModule } from '@bgaldino/nestjs-rabbitmq';
|
|
|
71
76
|
imports: [
|
|
72
77
|
RabbitMQModule.forRoot({
|
|
73
78
|
connectionString: 'amqp://user:password@localhost:5672/vhost',
|
|
74
|
-
delayExchangeName: 'my_app',
|
|
75
79
|
assertExchanges: [
|
|
76
80
|
{ name: 'orders', type: 'topic' },
|
|
77
81
|
{ name: 'notifications', type: 'fanout' },
|
|
78
82
|
],
|
|
79
83
|
}),
|
|
84
|
+
RabbitMQModule.withConsumers(),
|
|
80
85
|
],
|
|
81
86
|
})
|
|
82
87
|
export class AppModule {}
|
|
@@ -96,7 +101,6 @@ class RabbitConfig implements RabbitMQOptionsFactory {
|
|
|
96
101
|
createRabbitOptions(): ModuleOptions {
|
|
97
102
|
return {
|
|
98
103
|
connectionString: this.configService.get('RABBIT_URL'),
|
|
99
|
-
delayExchangeName: 'my_app',
|
|
100
104
|
assertExchanges: [
|
|
101
105
|
{ name: 'orders', type: 'topic' },
|
|
102
106
|
],
|
|
@@ -121,7 +125,6 @@ You can also use `useFactory` directly:
|
|
|
121
125
|
RabbitMQModule.forRootAsync({
|
|
122
126
|
useFactory: (configService: ConfigService) => ({
|
|
123
127
|
connectionString: configService.get('RABBIT_URL'),
|
|
124
|
-
delayExchangeName: 'my_app',
|
|
125
128
|
assertExchanges: [],
|
|
126
129
|
}),
|
|
127
130
|
inject: [ConfigService],
|
|
@@ -139,6 +142,81 @@ All queues are created as [quorum queues](https://www.rabbitmq.com/docs/quorum-q
|
|
|
139
142
|
by default. Consumers do not create exchanges, they only bind to exchanges
|
|
140
143
|
that already exist (declared via `assertExchanges`).
|
|
141
144
|
|
|
145
|
+
Consumers are only activated when `RabbitMQModule.withConsumers()` is imported.
|
|
146
|
+
Without it, no consumer connections are opened and no messages are consumed.
|
|
147
|
+
|
|
148
|
+
### Enabling consumers
|
|
149
|
+
|
|
150
|
+
Import `withConsumers()` alongside `forRoot()` to enable consumer discovery
|
|
151
|
+
and activation. The no-arg form discovers all `@RabbitConsumer` decorated
|
|
152
|
+
methods across the application and processes all `consumerChannels` from the
|
|
153
|
+
connection config:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
@Module({
|
|
157
|
+
imports: [
|
|
158
|
+
RabbitMQModule.forRoot({ ... }),
|
|
159
|
+
RabbitMQModule.withConsumers(),
|
|
160
|
+
],
|
|
161
|
+
})
|
|
162
|
+
export class AppModule {}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Selective consumer activation
|
|
166
|
+
|
|
167
|
+
When your application has multiple deployments (e.g., an API server and a
|
|
168
|
+
background worker), you can pass explicit handler classes to `withConsumers()`
|
|
169
|
+
to control which consumers are activated in each deployment:
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// API deployment — publish only, no consumers
|
|
173
|
+
@Module({
|
|
174
|
+
imports: [
|
|
175
|
+
RabbitMQModule.forRoot({ ... }),
|
|
176
|
+
],
|
|
177
|
+
})
|
|
178
|
+
export class ApiAppModule {}
|
|
179
|
+
|
|
180
|
+
// Worker deployment — only order and payment consumers
|
|
181
|
+
@Module({
|
|
182
|
+
imports: [
|
|
183
|
+
RabbitMQModule.forRoot({ ... }),
|
|
184
|
+
RabbitMQModule.withConsumers([OrderHandler, PaymentHandler]),
|
|
185
|
+
],
|
|
186
|
+
})
|
|
187
|
+
export class WorkerAppModule {}
|
|
188
|
+
|
|
189
|
+
// Report deployment — only report consumers
|
|
190
|
+
@Module({
|
|
191
|
+
imports: [
|
|
192
|
+
RabbitMQModule.forRoot({ ... }),
|
|
193
|
+
RabbitMQModule.withConsumers([ReportHandler]),
|
|
194
|
+
],
|
|
195
|
+
})
|
|
196
|
+
export class ReportAppModule {}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
When handler classes are passed, only `@RabbitConsumer` methods on those
|
|
200
|
+
classes are activated. Config consumers (`consumerChannels`) are always
|
|
201
|
+
processed regardless.
|
|
202
|
+
|
|
203
|
+
Keep in mind that all `@RabbitConsumer` methods on a given class are
|
|
204
|
+
activated together. If a class has consumers meant for different deployments,
|
|
205
|
+
split it into separate classes — one per deployment concern:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// Each class serves a single deployment
|
|
209
|
+
class OrderCreateHandler {
|
|
210
|
+
@RabbitConsumer({ queue: 'orders.create', ... })
|
|
211
|
+
async handle() { ... }
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
class OrderReportHandler {
|
|
215
|
+
@RabbitConsumer({ queue: 'orders.report', ... })
|
|
216
|
+
async handle() { ... }
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
142
220
|
### Decorator-based consumers
|
|
143
221
|
|
|
144
222
|
Decorate any method with `@RabbitConsumer()` and the library will
|
|
@@ -178,7 +256,6 @@ import { defineRabbitConsumer } from '@bgaldino/nestjs-rabbitmq';
|
|
|
178
256
|
|
|
179
257
|
RabbitMQModule.forRoot({
|
|
180
258
|
connectionString: 'amqp://localhost',
|
|
181
|
-
delayExchangeName: 'my_app',
|
|
182
259
|
assertExchanges: [{ name: 'orders', type: 'topic' }],
|
|
183
260
|
consumerChannels: [
|
|
184
261
|
defineRabbitConsumer({
|
|
@@ -252,32 +329,6 @@ export class OrderService implements ConsumerHandler<OrderPayload> {
|
|
|
252
329
|
}
|
|
253
330
|
```
|
|
254
331
|
|
|
255
|
-
### Consumer groups
|
|
256
|
-
|
|
257
|
-
Groups allow you to control which consumers are enabled on a given deployment.
|
|
258
|
-
This is useful when multiple instances of the same application serve different
|
|
259
|
-
roles.
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
@RabbitConsumer({
|
|
263
|
-
queue: 'heavy.processing',
|
|
264
|
-
exchangeName: 'jobs',
|
|
265
|
-
routingKey: 'heavy.*',
|
|
266
|
-
group: 'workers',
|
|
267
|
-
})
|
|
268
|
-
async processHeavyJob(content: any) { ... }
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
The active group is determined by:
|
|
272
|
-
|
|
273
|
-
1. The `RMQ_CONSUMER_GROUP` environment variable (highest priority)
|
|
274
|
-
2. The `group` parameter passed to `createConsumers(group)`
|
|
275
|
-
3. Defaults to `"rabbit-default"`
|
|
276
|
-
|
|
277
|
-
Consumers without an explicit group are assigned to the active group and will
|
|
278
|
-
always be initialized. Consumers with a group that does not match the active
|
|
279
|
-
group are skipped.
|
|
280
|
-
|
|
281
332
|
## Publishers
|
|
282
333
|
|
|
283
334
|
### Publishing messages
|
|
@@ -325,7 +376,7 @@ additional headers or properties.
|
|
|
325
376
|
If your application needs to consume from or publish to multiple RabbitMQ
|
|
326
377
|
vhosts (or entirely different brokers), you can use named connections.
|
|
327
378
|
Each connection is a self-contained unit with its own `connectionString`,
|
|
328
|
-
`
|
|
379
|
+
`assertExchanges`, and `consumerChannels`.
|
|
329
380
|
|
|
330
381
|
### Named connections
|
|
331
382
|
|
|
@@ -340,13 +391,11 @@ RabbitMQModule.forRoot({
|
|
|
340
391
|
{
|
|
341
392
|
name: 'default',
|
|
342
393
|
connectionString: 'amqp://localhost/main',
|
|
343
|
-
delayExchangeName: 'my_app',
|
|
344
394
|
assertExchanges: [{ name: 'orders', type: 'topic' }],
|
|
345
395
|
},
|
|
346
396
|
{
|
|
347
397
|
name: 'shared-bus',
|
|
348
398
|
connectionString: 'amqp://localhost/shared',
|
|
349
|
-
delayExchangeName: 'shared_app',
|
|
350
399
|
assertExchanges: [{ name: 'events', type: 'topic' }],
|
|
351
400
|
},
|
|
352
401
|
],
|
|
@@ -382,7 +431,6 @@ connections: [
|
|
|
382
431
|
{
|
|
383
432
|
name: 'default',
|
|
384
433
|
connectionString: 'amqp://localhost/main',
|
|
385
|
-
delayExchangeName: 'my_app',
|
|
386
434
|
assertExchanges: [{ name: 'orders', type: 'topic' }],
|
|
387
435
|
consumerChannels: [
|
|
388
436
|
defineRabbitConsumer({
|
|
@@ -423,13 +471,13 @@ back to the original queue for another attempt.
|
|
|
423
471
|
retryStrategy: {
|
|
424
472
|
enabled: true,
|
|
425
473
|
maxAttempts: 5,
|
|
426
|
-
|
|
474
|
+
retryFn: (content, attempt, error) => attempt * 5000,
|
|
427
475
|
},
|
|
428
476
|
})
|
|
429
477
|
async processOrder(content: OrderPayload) { ... }
|
|
430
478
|
```
|
|
431
479
|
|
|
432
|
-
The `
|
|
480
|
+
The `retryFn` callback receives the message content, the current attempt number,
|
|
433
481
|
and the error that was thrown. It should return the delay in milliseconds
|
|
434
482
|
before the next retry. The return value controls the behavior:
|
|
435
483
|
|
|
@@ -443,7 +491,7 @@ before the next retry. The return value controls the behavior:
|
|
|
443
491
|
|
|
444
492
|
- `enabled`: true
|
|
445
493
|
- `maxAttempts`: 5
|
|
446
|
-
- `
|
|
494
|
+
- `retryFn`: () => 5000
|
|
447
495
|
|
|
448
496
|
You can also give a "string" value referring a method of the same class,
|
|
449
497
|
following the interface:
|
|
@@ -457,7 +505,7 @@ to the dead letter queue.
|
|
|
457
505
|
|
|
458
506
|
## Dead Letter Strategy
|
|
459
507
|
|
|
460
|
-
Each consumer can define a `
|
|
508
|
+
Each consumer can define a `dlqStrategy` to control what happens when
|
|
461
509
|
a message exhausts all retry attempts:
|
|
462
510
|
|
|
463
511
|
```typescript
|
|
@@ -465,9 +513,9 @@ a message exhausts all retry attempts:
|
|
|
465
513
|
queue: 'order.process',
|
|
466
514
|
exchangeName: 'orders',
|
|
467
515
|
routingKey: 'order.process',
|
|
468
|
-
|
|
516
|
+
dlqStrategy: {
|
|
469
517
|
suffix: '.dlq',
|
|
470
|
-
|
|
518
|
+
dlqFn: async (content) => {
|
|
471
519
|
await alertService.notify('Order processing failed', content);
|
|
472
520
|
return true;
|
|
473
521
|
},
|
|
@@ -479,7 +527,7 @@ async processOrder(content: OrderPayload) { ... }
|
|
|
479
527
|
The `suffix` controls the name of the dead letter queue. Defaults to `.dlq`,
|
|
480
528
|
resulting in a queue named `{queue}.dlq`.
|
|
481
529
|
|
|
482
|
-
The `
|
|
530
|
+
The `dlqFn` is executed before sending the message to the DLQ. It receives
|
|
483
531
|
the raw message content and should return a boolean:
|
|
484
532
|
|
|
485
533
|
- `true`: the message is forwarded to the DLQ after the callback executes
|
|
@@ -488,34 +536,12 @@ the raw message content and should return a boolean:
|
|
|
488
536
|
If the callback throws an error, the message is forwarded to the DLQ regardless.
|
|
489
537
|
|
|
490
538
|
Like the `retryStrategy`, you can pass a "string" of the method name you want
|
|
491
|
-
to call if it is in the same class. The method should implement the interface:
|
|
539
|
+
to call if it is in the same class. The method should implement the `IDLQFn` interface:
|
|
492
540
|
|
|
493
541
|
```typescript
|
|
494
542
|
function (content: T): Promise<boolean> | boolean;
|
|
495
543
|
```
|
|
496
544
|
|
|
497
|
-
## Disabling the automatic ack
|
|
498
|
-
|
|
499
|
-
By default, the consumer automatically acknowledges the message after the
|
|
500
|
-
handler completes. If you need manual control over acknowledgement, disable it:
|
|
501
|
-
|
|
502
|
-
```typescript
|
|
503
|
-
@RabbitConsumer({
|
|
504
|
-
queue: 'order.process',
|
|
505
|
-
exchangeName: 'orders',
|
|
506
|
-
routingKey: 'order.process',
|
|
507
|
-
autoAck: false,
|
|
508
|
-
})
|
|
509
|
-
async processOrder(content: OrderPayload, params: MessageParams) {
|
|
510
|
-
// do work
|
|
511
|
-
params.channel.ack(params.message);
|
|
512
|
-
}
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
When `autoAck` is disabled, you are responsible for calling `channel.ack()` or
|
|
516
|
-
`channel.nack()`. If you do not acknowledge the message, it will remain
|
|
517
|
-
unacknowledged and RabbitMQ will redeliver it when the consumer disconnects.
|
|
518
|
-
|
|
519
545
|
## Custom Header Metadata
|
|
520
546
|
|
|
521
547
|
Every published message includes the following custom headers automatically:
|
|
@@ -537,41 +563,6 @@ when available, falling back to the message's current routing key.
|
|
|
537
563
|
|
|
538
564
|
## Extra Options
|
|
539
565
|
|
|
540
|
-
### Consumer manual loading
|
|
541
|
-
|
|
542
|
-
Consumers are attached during the `OnApplicationBootstrap` lifecycle, which
|
|
543
|
-
means the application begins receiving messages as soon as all modules are
|
|
544
|
-
initialized, but before `app.listen()` resolves.
|
|
545
|
-
|
|
546
|
-
If you need consumers to start only after the HTTP server is ready (or need
|
|
547
|
-
to defer startup for any other reason), set `consumerManualLoad: true` and
|
|
548
|
-
call the initialization manually:
|
|
549
|
-
|
|
550
|
-
```typescript
|
|
551
|
-
RabbitMQModule.forRoot({
|
|
552
|
-
connectionString: 'amqp://localhost',
|
|
553
|
-
delayExchangeName: 'my_app',
|
|
554
|
-
assertExchanges: [],
|
|
555
|
-
extraOptions: {
|
|
556
|
-
consumerManualLoad: true,
|
|
557
|
-
},
|
|
558
|
-
})
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
```typescript
|
|
562
|
-
async function bootstrap() {
|
|
563
|
-
const app = await NestFactory.create(AppModule);
|
|
564
|
-
await app.listen(3000);
|
|
565
|
-
|
|
566
|
-
const rabbit = app.get(RabbitMQService);
|
|
567
|
-
await rabbit.startConsumers();
|
|
568
|
-
}
|
|
569
|
-
bootstrap();
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
You can also pass a group name to `startConsumers(group)` to initialize only consumers
|
|
573
|
-
belonging to that group.
|
|
574
|
-
|
|
575
566
|
### Message inspection and logging
|
|
576
567
|
|
|
577
568
|
You can inspect consumer and publisher messages by setting `extraOptions.logType`
|
|
@@ -595,12 +586,15 @@ connections:
|
|
|
595
586
|
const rabbit = app.get(RabbitMQService);
|
|
596
587
|
|
|
597
588
|
// Check all connections (returns 0 if any connection is offline)
|
|
598
|
-
const status = rabbit.checkHealth(); // 1 = online, 0 = offline
|
|
589
|
+
const status = await rabbit.checkHealth(); // 1 = online, 0 = offline
|
|
599
590
|
|
|
600
591
|
// Check a specific connection
|
|
601
|
-
const sharedStatus = rabbit.checkHealth('shared-bus');
|
|
592
|
+
const sharedStatus = await rabbit.checkHealth('shared-bus');
|
|
602
593
|
```
|
|
603
594
|
|
|
595
|
+
When `withConsumers()` is not imported, the health check only verifies
|
|
596
|
+
publisher connections.
|
|
597
|
+
|
|
604
598
|
## Building locally
|
|
605
599
|
|
|
606
600
|
```shell
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LogType, ModuleOptions } from "./rabbitmq.types";
|
|
3
|
-
import { ClassDiscovery } from "./class-discovery";
|
|
1
|
+
import { OnApplicationShutdown, OnModuleInit } from "@nestjs/common";
|
|
2
|
+
import { LogType, ModuleOptions, RabbitMQConsumerResolved } from "./rabbitmq.types";
|
|
4
3
|
import { ConnectionHolder } from "./connection-factory";
|
|
5
|
-
export declare class AMQPConnectionManager implements OnModuleInit,
|
|
6
|
-
private readonly classDiscovery;
|
|
4
|
+
export declare class AMQPConnectionManager implements OnModuleInit, OnApplicationShutdown {
|
|
7
5
|
private readonly logger;
|
|
8
6
|
private defaultOptions;
|
|
9
7
|
private opts;
|
|
10
8
|
private connections;
|
|
11
9
|
private connectionFactory;
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
private resolveConnection;
|
|
11
|
+
private readonly connectionReady;
|
|
12
|
+
constructor(options: ModuleOptions);
|
|
14
13
|
onModuleInit(): Promise<void>;
|
|
15
|
-
|
|
14
|
+
private connectPublishers;
|
|
16
15
|
getLogType(): LogType;
|
|
16
|
+
ensureConnected(): Promise<void>;
|
|
17
17
|
getConnectionHolder(name?: string): ConnectionHolder;
|
|
18
18
|
getAllConnections(): ConnectionHolder[];
|
|
19
|
-
|
|
19
|
+
activateConsumers(consumers: RabbitMQConsumerResolved[]): Promise<void>;
|
|
20
20
|
onApplicationShutdown(): Promise<void>;
|
|
21
21
|
private resolveConnections;
|
|
22
|
-
private connect;
|
|
23
22
|
private buildConsumer;
|
|
24
23
|
}
|
|
@@ -18,93 +18,76 @@ const common_1 = require("@nestjs/common");
|
|
|
18
18
|
const helper_1 = require("./helper");
|
|
19
19
|
const rabbitmq_consumer_1 = require("./rabbitmq-consumer");
|
|
20
20
|
const rabbitmq_constants_1 = require("./rabbitmq.constants");
|
|
21
|
-
const class_discovery_1 = require("./class-discovery");
|
|
22
21
|
const connection_factory_1 = require("./connection-factory");
|
|
23
22
|
let AMQPConnectionManager = AMQPConnectionManager_1 = class AMQPConnectionManager {
|
|
24
|
-
constructor(options
|
|
23
|
+
constructor(options) {
|
|
25
24
|
var _a, _b;
|
|
26
|
-
this.
|
|
25
|
+
this.logger = new common_1.Logger(AMQPConnectionManager_1.name);
|
|
27
26
|
this.defaultOptions = {
|
|
28
27
|
extraOptions: {
|
|
29
28
|
logType: "none",
|
|
30
|
-
consumerManualLoad: false,
|
|
31
29
|
heartbeatIntervalInSeconds: 0,
|
|
32
30
|
reconnectTimeInSeconds: 5,
|
|
33
31
|
},
|
|
34
32
|
};
|
|
35
33
|
this.connections = new Map();
|
|
36
|
-
this.consumerInitialized = false;
|
|
37
34
|
this.opts = (0, helper_1.merge)(this.defaultOptions, options);
|
|
38
35
|
this.opts.extraOptions.logType = (_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.RABBITMQ_LOG_TYPE) !== null && _b !== void 0 ? _b : this.opts.extraOptions.logType;
|
|
39
|
-
this.logger = new common_1.Logger(AMQPConnectionManager_1.name);
|
|
40
36
|
this.connectionFactory = new connection_factory_1.ConnectionFactory(this.opts);
|
|
37
|
+
this.connectionReady = new Promise(resolve => {
|
|
38
|
+
this.resolveConnection = resolve;
|
|
39
|
+
});
|
|
41
40
|
}
|
|
42
41
|
async onModuleInit() {
|
|
43
|
-
|
|
42
|
+
await this.connectPublishers();
|
|
43
|
+
this.resolveConnection();
|
|
44
44
|
}
|
|
45
|
-
async
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
async connectPublishers() {
|
|
46
|
+
const configs = this.resolveConnections();
|
|
47
|
+
for (const config of configs) {
|
|
48
|
+
const holder = await this.connectionFactory.createPublisher(config);
|
|
49
|
+
this.connections.set(config.name, holder);
|
|
50
|
+
}
|
|
50
51
|
}
|
|
51
52
|
getLogType() {
|
|
52
53
|
return this.opts.extraOptions.logType;
|
|
53
54
|
}
|
|
55
|
+
async ensureConnected() {
|
|
56
|
+
await this.connectionReady;
|
|
57
|
+
}
|
|
54
58
|
getConnectionHolder(name = "default") {
|
|
55
59
|
const holder = this.connections.get(name);
|
|
56
60
|
if (!holder) {
|
|
57
|
-
|
|
61
|
+
const available = [...this.connections.keys()];
|
|
62
|
+
const hint = available.length === 0
|
|
63
|
+
? " Connections may not have been established yet. Ensure RabbitMQModule is imported before modules that depend on it."
|
|
64
|
+
: "";
|
|
65
|
+
throw new Error(`RabbitMQModule: Connection "${name}" not found. Available: ${available.join(", ")}.${hint}`);
|
|
58
66
|
}
|
|
59
67
|
return holder;
|
|
60
68
|
}
|
|
61
69
|
getAllConnections() {
|
|
62
70
|
return [...this.connections.values()];
|
|
63
71
|
}
|
|
64
|
-
async
|
|
65
|
-
var _a
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.logger.log(`Initializing consumers with group: ${consumerGroup}`);
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
this.logger.log(`No groups associated, initializing all consumers without groups`);
|
|
74
|
-
}
|
|
75
|
-
const allConsumers = [];
|
|
76
|
-
for (const [connName, holder] of this.connections) {
|
|
77
|
-
const configConsumers = this.classDiscovery
|
|
78
|
-
.getConfigConsumers((_f = holder.config.consumerChannels) !== null && _f !== void 0 ? _f : [])
|
|
79
|
-
.map(c => (Object.assign(Object.assign({}, c), { connection: connName })));
|
|
80
|
-
allConsumers.push(...configConsumers);
|
|
72
|
+
async activateConsumers(consumers) {
|
|
73
|
+
var _a;
|
|
74
|
+
for (const [, holder] of this.connections) {
|
|
75
|
+
if (!holder.consumerConn) {
|
|
76
|
+
await this.connectionFactory.attachConsumer(holder);
|
|
77
|
+
}
|
|
81
78
|
}
|
|
82
|
-
const decoratorConsumers = this.classDiscovery.discoverDecoratedConsumers();
|
|
83
|
-
allConsumers.push(...decoratorConsumers);
|
|
84
79
|
const dupQueues = new Set();
|
|
85
|
-
for (const c of
|
|
86
|
-
if (dupQueues.has(c.queue))
|
|
87
|
-
throw new Error(`
|
|
88
|
-
}
|
|
80
|
+
for (const c of consumers) {
|
|
81
|
+
if (dupQueues.has(c.queue))
|
|
82
|
+
throw new Error(`Duplicate queue "${c.queue}"`);
|
|
89
83
|
dupQueues.add(c.queue);
|
|
90
84
|
}
|
|
91
|
-
for (const consumer of
|
|
92
|
-
|
|
93
|
-
if (consumer.group !== consumerGroup)
|
|
94
|
-
continue;
|
|
95
|
-
if (consumer.enabled === false) {
|
|
96
|
-
this.logger.debug({ type: "initialization", title: `[AMQP] [INIT] Consumer ${consumer.queue} is DISABLED` });
|
|
85
|
+
for (const consumer of consumers) {
|
|
86
|
+
if (consumer.enabled === false)
|
|
97
87
|
continue;
|
|
98
|
-
|
|
99
|
-
const connName = (_h = consumer.connection) !== null && _h !== void 0 ? _h : "default";
|
|
88
|
+
const connName = (_a = consumer.connection) !== null && _a !== void 0 ? _a : "default";
|
|
100
89
|
await this.buildConsumer(connName).createConsumer(consumer, consumer.handler);
|
|
101
|
-
this.logger.debug({
|
|
102
|
-
type: "initialization",
|
|
103
|
-
title: `[AMQP] [INIT] Initializing consumer ${consumer.queue}`,
|
|
104
|
-
binding: { exchange: consumer.exchangeName, routingKey: consumer.routingKey, group: consumer.group },
|
|
105
|
-
});
|
|
106
90
|
}
|
|
107
|
-
this.consumerInitialized = true;
|
|
108
91
|
}
|
|
109
92
|
async onApplicationShutdown() {
|
|
110
93
|
var _a, _b;
|
|
@@ -129,27 +112,19 @@ let AMQPConnectionManager = AMQPConnectionManager_1 = class AMQPConnectionManage
|
|
|
129
112
|
return [{
|
|
130
113
|
name: "default",
|
|
131
114
|
connectionString: this.opts.connectionString,
|
|
132
|
-
delayExchangeName: this.opts.delayExchangeName,
|
|
133
115
|
assertExchanges: this.opts.assertExchanges,
|
|
134
116
|
consumerChannels: this.opts.consumerChannels,
|
|
135
117
|
}];
|
|
136
118
|
}
|
|
137
|
-
async connect() {
|
|
138
|
-
const configs = this.resolveConnections();
|
|
139
|
-
for (const config of configs) {
|
|
140
|
-
const holder = await this.connectionFactory.create(config);
|
|
141
|
-
this.connections.set(config.name, holder);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
119
|
buildConsumer(connectionName = "default") {
|
|
145
120
|
const holder = this.getConnectionHolder(connectionName);
|
|
146
|
-
return new rabbitmq_consumer_1.RabbitMQConsumer(holder.consumerConn,
|
|
121
|
+
return new rabbitmq_consumer_1.RabbitMQConsumer(holder.consumerConn, this.opts.extraOptions.logType, holder.publisherWrapper);
|
|
147
122
|
}
|
|
148
123
|
};
|
|
149
124
|
exports.AMQPConnectionManager = AMQPConnectionManager;
|
|
150
125
|
exports.AMQPConnectionManager = AMQPConnectionManager = AMQPConnectionManager_1 = __decorate([
|
|
151
126
|
(0, common_1.Injectable)(),
|
|
152
127
|
__param(0, (0, common_1.Inject)(rabbitmq_constants_1.RABBIT_OPTIONS)),
|
|
153
|
-
__metadata("design:paramtypes", [Object
|
|
128
|
+
__metadata("design:paramtypes", [Object])
|
|
154
129
|
], AMQPConnectionManager);
|
|
155
130
|
//# sourceMappingURL=amqp-connection-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amqp-connection-manager.js","sourceRoot":"","sources":["../src/amqp-connection-manager.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"amqp-connection-manager.js","sourceRoot":"","sources":["../src/amqp-connection-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ export declare class ClassDiscovery {
|
|
|
9
9
|
constructor(discoveryService: DiscoveryService, metadataScanner: MetadataScanner, reflector: Reflector);
|
|
10
10
|
getProviderInstance<T>(provider: Type<T>): T;
|
|
11
11
|
discoverDecoratedConsumers(): Array<RabbitMQConsumerResolved>;
|
|
12
|
+
discoverFromClasses(classes: Type[]): Array<RabbitMQConsumerResolved>;
|
|
12
13
|
getConfigConsumers(consumerList: Array<ConsumerChannel>): Array<RabbitMQConsumerResolved>;
|
|
13
14
|
private resolveStrategyMethods;
|
|
14
15
|
}
|
package/dist/class-discovery.js
CHANGED
|
@@ -55,6 +55,25 @@ let ClassDiscovery = class ClassDiscovery {
|
|
|
55
55
|
}
|
|
56
56
|
return discovered;
|
|
57
57
|
}
|
|
58
|
+
discoverFromClasses(classes) {
|
|
59
|
+
const discovered = [];
|
|
60
|
+
for (const cls of classes) {
|
|
61
|
+
const wrapper = this.wrappers.find(w => w.metatype === cls);
|
|
62
|
+
if (!(wrapper === null || wrapper === void 0 ? void 0 : wrapper.instance)) {
|
|
63
|
+
throw new Error(`RabbitMQModule: Provider ${cls.name} not found. Is it registered in a module?`);
|
|
64
|
+
}
|
|
65
|
+
const { instance } = wrapper;
|
|
66
|
+
const methods = this.metadataScanner.getAllMethodNames(instance);
|
|
67
|
+
for (const method of methods) {
|
|
68
|
+
const meta = this.reflector.get(rabbit_consumer_decorator_1.RABBIT_HANDLER_METADATA, instance[method]);
|
|
69
|
+
if (!meta)
|
|
70
|
+
continue;
|
|
71
|
+
this.resolveStrategyMethods(meta, instance);
|
|
72
|
+
discovered.push(Object.assign(Object.assign({}, meta), { handler: instance[method].bind(instance) }));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return discovered;
|
|
76
|
+
}
|
|
58
77
|
getConfigConsumers(consumerList) {
|
|
59
78
|
const consumers = [];
|
|
60
79
|
for (const consumer of consumerList !== null && consumerList !== void 0 ? consumerList : []) {
|
|
@@ -71,19 +90,19 @@ let ClassDiscovery = class ClassDiscovery {
|
|
|
71
90
|
resolveStrategyMethods(meta, instance) {
|
|
72
91
|
var _a, _b;
|
|
73
92
|
const className = instance.constructor.name;
|
|
74
|
-
if (typeof ((_a = meta.retryStrategy) === null || _a === void 0 ? void 0 : _a.
|
|
75
|
-
const fn = instance[meta.retryStrategy.
|
|
93
|
+
if (typeof ((_a = meta.retryStrategy) === null || _a === void 0 ? void 0 : _a.retryFn) === "string") {
|
|
94
|
+
const fn = instance[meta.retryStrategy.retryFn];
|
|
76
95
|
if (typeof fn !== "function") {
|
|
77
|
-
throw new Error(`RabbitMQModule: Method "${meta.retryStrategy.
|
|
96
|
+
throw new Error(`RabbitMQModule: Method "${meta.retryStrategy.retryFn}" not found on ${className}`);
|
|
78
97
|
}
|
|
79
|
-
meta.retryStrategy.
|
|
98
|
+
meta.retryStrategy.retryFn = fn.bind(instance);
|
|
80
99
|
}
|
|
81
|
-
if (typeof ((_b = meta.
|
|
82
|
-
const fn = instance[meta.
|
|
100
|
+
if (typeof ((_b = meta.dlqStrategy) === null || _b === void 0 ? void 0 : _b.dlqFn) === "string") {
|
|
101
|
+
const fn = instance[meta.dlqStrategy.dlqFn];
|
|
83
102
|
if (typeof fn !== "function") {
|
|
84
|
-
throw new Error(`RabbitMQModule: Method "${meta.
|
|
103
|
+
throw new Error(`RabbitMQModule: Method "${meta.dlqStrategy.dlqFn}" not found on ${className}`);
|
|
85
104
|
}
|
|
86
|
-
meta.
|
|
105
|
+
meta.dlqStrategy.dlqFn = fn.bind(instance);
|
|
87
106
|
}
|
|
88
107
|
}
|
|
89
108
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"class-discovery.js","sourceRoot":"","sources":["../src/class-discovery.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAkD;AAClD,uCAA4E;AAE5E,2EAAsE;AAI/D,IAAM,cAAc,GAApB,MAAM,cAAc;
|
|
1
|
+
{"version":3,"file":"class-discovery.js","sourceRoot":"","sources":["../src/class-discovery.ts"],"names":[],"mappings":"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"}
|