@niur/nestjs-service-bus
Version:
NestJS Azure Service Bus Microservice Transport
130 lines (110 loc) • 3.57 kB
text/typescript
import {
Server,
WritePacket,
CustomTransportStrategy,
} from "@nestjs/microservices";
import {
MessageHandlers,
ProcessErrorArgs,
ServiceBusClient,
ServiceBusMessage,
ServiceBusReceivedMessage,
} from "@azure/service-bus";
import { AzureServiceBusContext } from "../azure-service-bus.context";
import { AzureServiceBusOptions } from "../interfaces";
import { SbSubscriberMetadata } from "../metadata";
export class AzureServiceBusServer
extends Server
implements CustomTransportStrategy
{
private sbClient: ServiceBusClient;
constructor(protected readonly options: AzureServiceBusOptions) {
super();
this.initializeSerializer(options);
this.initializeDeserializer(options);
}
async listen(callback: (...optionalParams: unknown[]) => any) {
try {
this.sbClient = this.createServiceBusClient();
await this.start(callback);
} catch (err) {
callback(err);
}
}
async start(
callback: (err?: unknown, ...optionalParams: unknown[]) => void
): Promise<void> {
await this.bindEvents();
callback();
}
async bindEvents(): Promise<void> {
const subscribe = async (pattern: string) => {
const {
metaOptions: {
topic,
subscription: name,
subQueueType,
skipParsingBodyAsJson,
receiveMode,
options,
},
}: SbSubscriberMetadata = JSON.parse(pattern);
const receiver = this.sbClient.createReceiver(topic, name, {
receiveMode,
subQueueType,
skipParsingBodyAsJson,
});
receiver.subscribe(this.createMessageHandlers(pattern), options);
await receiver.close();
};
const registeredPatterns = [...this.messageHandlers.keys()];
await Promise.all(registeredPatterns.map(subscribe));
}
public createMessageHandlers = (pattern: string): MessageHandlers => ({
processMessage: async (receivedMessage: ServiceBusReceivedMessage) =>
await this.handleMessage(receivedMessage, pattern),
processError: async (args: ProcessErrorArgs): Promise<void> => {
return new Promise<void>(() => {
console.error(`Error processing message: ${args.error}`);
});
},
});
public async handleMessage(
receivedMessage: ServiceBusReceivedMessage,
pattern: string
): Promise<void> {
const partialPacket = { data: receivedMessage, pattern };
const packet = await this.deserializer.deserialize(partialPacket);
if (!receivedMessage.replyTo) {
const sbContext = new AzureServiceBusContext([]);
return this.handleEvent(packet.pattern, packet, sbContext);
}
const publish = this.getPublisher(
receivedMessage.replyTo,
receivedMessage.messageId as string
);
const handler = this.getHandlerByPattern(pattern);
const response$ = this.transformToObservable(
await handler(receivedMessage)
);
response$ && this.send(response$, publish);
}
public getPublisher(replyTo: string, correlationId: string) {
return async (data: WritePacket) => {
const sender = this.sbClient.createSender(replyTo);
const responseMessage = {
correlationId,
body: data.response,
} as ServiceBusMessage;
await sender.sendMessages([responseMessage]);
await sender.close();
};
}
createServiceBusClient(): ServiceBusClient {
const { connectionString, options } = this.options;
return new ServiceBusClient(connectionString, options);
}
async close(): Promise<void> {
await this.sbClient?.close();
}
}