Skip to content

Commit e0d1364

Browse files
committed
feature(@nestjs/microservices) Added additional options and fixes
1 parent bb73598 commit e0d1364

8 files changed

Lines changed: 107 additions & 58 deletions

File tree

package-lock.json

Lines changed: 8 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/common/enums/transport.enum.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export enum Transport {
44
NATS,
55
MQTT,
66
GRPC,
7+
RMQ
78
}

packages/common/interfaces/microservices/client-metadata.interface.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@ import {
55
NatsOptions,
66
MqttOptions,
77
GrpcOptions,
8+
RmqOptions
89
} from './microservice-configuration.interface';
910

1011
export interface ClientOptions {
1112
transport?: Transport;
1213
options?:
13-
| TcpClientOptions
14-
| RedisOptions
15-
| NatsOptions
16-
| MqttOptions
17-
| GrpcOptions;
14+
| TcpClientOptions
15+
| RedisOptions
16+
| NatsOptions
17+
| MqttOptions
18+
| GrpcOptions
19+
| RmqOptions;
1820
}
1921

2022
export interface TcpClientOptions {

packages/common/interfaces/microservices/microservice-configuration.interface.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { Transport } from '../../enums/transport.enum';
22
import { MqttClientOptions } from '../external/mqtt-options.interface';
33
import { CustomTransportStrategy } from './custom-transport-strategy.interface';
4+
import { Options } from 'amqplib';
45

56
export type MicroserviceOptions =
67
| GrpcOptions
78
| TcpOptions
89
| RedisOptions
910
| NatsOptions
1011
| MqttOptions
12+
| RmqOptions
1113
| CustomStrategy;
1214

1315
export interface CustomStrategy {
@@ -64,3 +66,14 @@ export interface NatsOptions {
6466
tls?: any;
6567
};
6668
}
69+
70+
export interface RmqOptions {
71+
transport?: Transport.RMQ;
72+
options?: {
73+
url?: string;
74+
queue?: string;
75+
prefetchCount?: number;
76+
isGlobalPrefetchCount?: boolean;
77+
queueOptions?: Options.AssertQueue;
78+
};
79+
}

packages/microservices/client/client-rmq.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Channel, Connection } from 'amqplib';
2-
import { CONNECT_EVENT, ERROR_EVENT, MESSAGE_EVENT, RQM_DEFAULT_URL, SUBSCRIBE, RQM_DEFAULT_QUEUE } from './../constants';
1+
import { Channel, Connection, Options } from 'amqplib';
2+
import { ERROR_EVENT, RQM_DEFAULT_URL, RQM_DEFAULT_QUEUE, RQM_DEFAULT_PREFETCH_COUNT, RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT, RQM_DEFAULT_QUEUE_OPTIONS } from './../constants';
33
import { Logger } from '@nestjs/common/services/logger.service';
44
import { loadPackage } from '@nestjs/common/utils/load-package.util';
55
import { ClientProxy } from './client-proxy';
@@ -14,30 +14,36 @@ export class ClientRMQ extends ClientProxy {
1414
private channel: Channel = null;
1515
private url: string;
1616
private queue: string;
17+
private prefetchCount: number;
18+
private isGlobalPrefetchCount: boolean;
19+
private queueOptions: Options.AssertQueue
1720
private replyQueue: string;
1821
private responseEmitter: EventEmitter;
19-
22+
2023
constructor(
2124
private readonly options: ClientOptions) {
2225
super();
2326
this.url =
2427
this.getOptionsProp<RmqOptions>(this.options, 'url') || RQM_DEFAULT_URL;
2528
this.queue =
2629
this.getOptionsProp<RmqOptions>(this.options, 'queue') || RQM_DEFAULT_QUEUE;
30+
this.prefetchCount =
31+
this.getOptionsProp<RmqOptions>(this.options, 'prefetchCount') || RQM_DEFAULT_PREFETCH_COUNT;
32+
this.isGlobalPrefetchCount =
33+
this.getOptionsProp<RmqOptions>(this.options, 'isGlobalPrefetchCount') || RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT;
34+
this.queueOptions =
35+
this.getOptionsProp<RmqOptions>(this.options, 'queueOptions') || RQM_DEFAULT_QUEUE_OPTIONS;
2736
rqmPackage = loadPackage('amqplib', ClientRMQ.name);
2837
this.connect();
2938
}
3039

31-
protected async publish(messageObj, callback: (err, result, disposed?: boolean) => void) {
40+
protected publish(messageObj, callback: (err, result, disposed?: boolean) => void) {
3241
try {
33-
if (!this.client) {
34-
await this.connect();
35-
}
3642
let correlationId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
3743
this.responseEmitter.once(correlationId, msg => {
3844
this.handleMessage(msg, callback);
3945
});
40-
this.channel.sendToQueue(this.queue, Buffer.from(JSON.stringify(messageObj)), {
46+
this.channel.sendToQueue(this.queue, Buffer.from(JSON.stringify(messageObj)), {
4147
replyTo: this.replyQueue,
4248
correlationId: correlationId
4349
});
@@ -48,7 +54,7 @@ export class ClientRMQ extends ClientProxy {
4854
}
4955

5056
private async handleMessage(message, callback): Promise<void> {
51-
if(message) {
57+
if (message) {
5258
const { content } = message;
5359
const { err, response, isDisposed } = JSON.parse(content.toString());
5460
if (isDisposed || err) {
@@ -61,7 +67,7 @@ export class ClientRMQ extends ClientProxy {
6167
callback({
6268
err,
6369
response,
64-
});
70+
});
6571
}
6672
}
6773

@@ -80,11 +86,15 @@ export class ClientRMQ extends ClientProxy {
8086
}, { noAck: true });
8187
}
8288

83-
public async connect():Promise<any> {
89+
public async connect(): Promise<any> {
90+
if (this.client && this.channel) {
91+
return Promise.resolve();
92+
}
8493
return new Promise(async (resolve, reject) => {
8594
this.client = await rqmPackage.connect(this.url);
8695
this.channel = await this.client.createChannel();
87-
await this.channel.assertQueue(this.queue, { durable: false });
96+
await this.channel.assertQueue(this.queue, this.queueOptions);
97+
await this.channel.prefetch(this.prefetchCount, this.isGlobalPrefetchCount);
8898
this.replyQueue = (await this.channel.assertQueue('', { exclusive: true })).queue;
8999
this.responseEmitter = new EventEmitter();
90100
this.responseEmitter.setMaxListeners(0);

packages/microservices/constants.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ export const NATS_DEFAULT_URL = 'nats://localhost:4222';
55
export const MQTT_DEFAULT_URL = 'mqtt://localhost:1883';
66
export const GRPC_DEFAULT_URL = 'localhost:5000';
77
export const RQM_DEFAULT_URL = 'amqp://localhost';
8-
export const RQM_DEFAULT_QUEUE = 'default';
98

109
export const CONNECT_EVENT = 'connect';
1110
export const MESSAGE_EVENT = 'message';
@@ -19,3 +18,8 @@ export const CLIENT_CONFIGURATION_METADATA = 'client';
1918
export const CLIENT_METADATA = '__isClient';
2019
export const PATTERN_HANDLER_METADATA = '__isPattern';
2120
export const NO_PATTERN_MESSAGE = `There is no equivalent message pattern defined in the remote service.`;
21+
22+
export const RQM_DEFAULT_QUEUE = 'default';
23+
export const RQM_DEFAULT_PREFETCH_COUNT = 0;
24+
export const RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT = false;
25+
export const RQM_DEFAULT_QUEUE_OPTIONS = {};

packages/microservices/interfaces/microservice-configuration.interface.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { MqttClientOptions } from '@nestjs/common/interfaces/external/mqtt-options.interface';
22
import { Transport } from '../enums/transport.enum';
33
import { Server } from './../server/server';
4+
import { Options } from 'amqplib';
45
import { CustomTransportStrategy } from './custom-transport-strategy.interface';
56

67
export type MicroserviceOptions =
@@ -72,5 +73,8 @@ export interface RmqOptions {
7273
options?: {
7374
url?: string;
7475
queue?: string;
76+
prefetchCount?: number;
77+
isGlobalPrefetchCount?: boolean;
78+
queueOptions?: Options.AssertQueue;
7579
};
7680
}
Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Server } from './server';
2-
import { Channel, Connection } from 'amqplib';
3-
import { RQM_DEFAULT_URL , RQM_DEFAULT_QUEUE } from './../constants';
2+
import { Channel, Connection, Options } from 'amqplib';
3+
import { RQM_DEFAULT_URL, RQM_DEFAULT_QUEUE, RQM_DEFAULT_PREFETCH_COUNT, RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT, RQM_DEFAULT_QUEUE_OPTIONS } from './../constants';
44
import { CustomTransportStrategy, RmqOptions } from './../interfaces';
55
import { MicroserviceOptions } from '../interfaces/microservice-configuration.interface';
66
import { loadPackage } from '@nestjs/common/utils/load-package.util';
@@ -13,53 +13,63 @@ export class ServerRMQ extends Server implements CustomTransportStrategy {
1313
private channel: Channel = null;
1414
private url: string;
1515
private queue: string;
16+
private prefetchCount: number;
17+
private queueOptions: Options.AssertQueue
18+
private isGlobalPrefetchCount: boolean;
1619

1720
constructor(private readonly options: MicroserviceOptions) {
1821
super();
1922
this.url =
2023
this.getOptionsProp<RmqOptions>(this.options, 'url') || RQM_DEFAULT_URL;
2124
this.queue =
2225
this.getOptionsProp<RmqOptions>(this.options, 'queue') || RQM_DEFAULT_QUEUE;
26+
this.prefetchCount =
27+
this.getOptionsProp<RmqOptions>(this.options, 'prefetchCount') || RQM_DEFAULT_PREFETCH_COUNT;
28+
this.isGlobalPrefetchCount =
29+
this.getOptionsProp<RmqOptions>(this.options, 'isGlobalPrefetchCount') || RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT;
30+
this.queueOptions =
31+
this.getOptionsProp<RmqOptions>(this.options, 'queueOptions') || RQM_DEFAULT_QUEUE_OPTIONS;
2332
rqmPackage = loadPackage('amqplib', ServerRMQ.name);
24-
}
33+
}
2534

26-
public async listen(callback: () => void): Promise<void> {
27-
await this.start(callback);
28-
this.channel.consume(this.queue, (msg) => this.handleMessage(msg) , {
29-
noAck: true,
30-
});
31-
}
35+
public async listen(callback: () => void): Promise<void> {
36+
await this.start(callback);
37+
this.channel.consume(this.queue, (msg) => this.handleMessage(msg), {
38+
noAck: true,
39+
});
40+
}
3241

33-
private async start(callback?: () => void) {
34-
try {
35-
this.server = await rqmPackage.connect(this.url);
36-
this.channel = await this.server.createChannel();
37-
this.channel.assertQueue(this.queue, { durable: false });
38-
} catch (err) {
39-
this.logger.error(err);
40-
}
41-
}
42+
private async start(callback?: () => void) {
43+
try {
44+
this.server = await rqmPackage.connect(this.url);
45+
this.channel = await this.server.createChannel();
46+
this.channel.assertQueue(this.queue, this.queueOptions);
47+
await this.channel.prefetch(this.prefetchCount, this.isGlobalPrefetchCount);
48+
} catch (err) {
49+
this.logger.error(err);
50+
}
51+
}
4252

43-
public close(): void {
44-
this.channel && this.channel.close();
45-
this.server && this.server.close();
46-
}
53+
public close(): void {
54+
this.channel && this.channel.close();
55+
this.server && this.server.close();
56+
}
4757

48-
private async handleMessage(message): Promise<void> {
49-
const { content, properties } = message;
50-
const messageObj = JSON.parse(content.toString());
51-
const handlers = this.getHandlers();
52-
const pattern = JSON.stringify(messageObj.pattern);
53-
if (!this.messageHandlers[pattern]) {
54-
return;
58+
private async handleMessage(message): Promise<void> {
59+
const { content, properties } = message;
60+
const messageObj = JSON.parse(content.toString());
61+
const handlers = this.getHandlers();
62+
const pattern = JSON.stringify(messageObj.pattern);
63+
if (!this.messageHandlers[pattern]) {
64+
return;
65+
}
66+
const handler = this.messageHandlers[pattern];
67+
const response$ = this.transformToObservable(await handler(messageObj.data)) as Observable<any>;
68+
response$ && this.send(response$, (data) => this.sendMessage(data, properties.replyTo, properties.correlationId));
5569
}
56-
const handler = this.messageHandlers[pattern];
57-
const response$ = this.transformToObservable(await handler(messageObj.data)) as Observable<any>;
58-
response$ && this.send(response$, (data) => this.sendMessage(data, properties.replyTo, properties.correlationId));
59-
}
6070

61-
private sendMessage(message, replyTo, correlationId): void {
62-
const buffer = Buffer.from(JSON.stringify(message));
63-
this.channel.sendToQueue(replyTo, buffer, {correlationId: correlationId});
64-
}
71+
private sendMessage(message, replyTo, correlationId): void {
72+
const buffer = Buffer.from(JSON.stringify(message));
73+
this.channel.sendToQueue(replyTo, buffer, { correlationId: correlationId });
74+
}
6575
}

0 commit comments

Comments
 (0)