nest-nsq-transport
Version:
NestJS microservice transport for NSQ
138 lines • 6.09 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NSQStrategy = void 0;
const common_1 = require("@nestjs/common");
const microservices_1 = require("@nestjs/microservices");
const nsqjs_1 = require("nsqjs");
const context_1 = require("./context");
const deferred_1 = require("./deferred");
const errors_1 = require("./errors");
const invariant_1 = require("./invariant");
const pattern_1 = require("./pattern");
const serialization_1 = require("./serialization");
const wait_group_1 = require("./wait-group");
class NSQStrategy extends microservices_1.Server {
opts;
logger = new common_1.Logger(NSQStrategy.name);
readers = new Map();
handlingMessagesWG = new wait_group_1.WaitGroup();
readersSetDeferred = new deferred_1.Deferred();
constructor(opts) {
super();
this.opts = opts;
this.deserializer = opts.deserializer ?? new serialization_1.StringDeserializer();
}
async listen(callback) {
this.readersSetDeferred.resolve();
await Promise.all([...this.readers.values()].map((reader) => new Promise((res, rej) => {
reader.on('ready', res);
reader.on('error', rej);
reader.connect();
})));
this.logger.log('start listening to messages');
if (callback)
callback();
}
addHandler(pattern, callback, isEventHandler, extras) {
const parsed = pattern_1.NSQPattern.parse(pattern);
if (!parsed)
return this.logger.debug(`skipping handler with pattern: ${JSON.stringify(pattern)}`);
if (!isEventHandler)
throw new errors_1.RPCNotSupported();
const reader = this.createOrGetReaderFor(parsed);
reader.on(parsed.discard ? 'discard' : 'message', this.handleMessage(parsed));
super.addHandler(pattern, callback, isEventHandler, extras);
}
async close() {
for (const reader of this.readers.values()) {
reader.pause();
}
await this.handlingMessagesWG.wait();
for (const reader of this.readers.values()) {
reader.close();
}
}
on(event, callback) {
void this.readersSetDeferred.promise.then(() => {
this.readers.forEach((reader) => {
// @ts-expect-error FIXME later
reader.on(event, callback);
});
});
}
// we have multiple underlying readers, so we return all of them
unwrap() {
return this.readers;
}
createOrGetReaderFor(pattern) {
const existing = this.readers.get(pattern.toString(true));
if (existing)
return existing;
const reader = this.createReaderFor(pattern);
this.readers.set(pattern.toString(true), reader);
return reader;
}
createReaderFor(pattern) {
const { topic, channel } = pattern;
const { requeueParams: _, ...readerOpts } = this.getOptionsByPattern(pattern);
const reader = new nsqjs_1.Reader(topic, channel, readerOpts);
const logPrefix = `reader for topic ${topic} and channel ${channel} status:`;
reader.on('not_ready', () => this.logger.log(`${logPrefix} not ready`));
reader.on('nsqd_connected', (host, port) => this.logger.log(`${logPrefix} not connected to nsqd ${host}:${port}`));
reader.on('nsqd_closed', (host, port) => this.logger.log(`${logPrefix} nsqd closed ${host}:${port}`));
reader.on('error', (error) => this.logger.error(`${logPrefix} ${error}`));
return reader;
}
getOptionsByPattern(pattern) {
return Object.assign({}, this.opts.defaultChannelOptions, this.opts.channels?.[pattern.topic]?.[pattern.channel]);
}
handleMessage(pattern) {
return async (message) => {
this.handlingMessagesWG.add(1);
const handler = this.getHandlerByPattern(pattern.toString());
(0, invariant_1.invariant)(handler, `no handler for pattern ${pattern}`);
const logAttributes = `message id=${message.id} attempt=${message.attempts} timestamp=${message.timestamp} topic=${pattern.topic} channel=${pattern.channel}${pattern.discard ? ' discarded' : ''}`;
this.logger.verbose(`${logAttributes} to be processed`);
let success = false;
try {
const packet = await this.deserializer.deserialize(message, {
pattern,
});
const ctx = new context_1.NSQContext([message, pattern]);
const result = await handler(packet.data, ctx);
if (result)
await result.toPromise();
this.logger.debug(`${logAttributes} handled successfully`);
message.finish();
success = true;
}
catch (e) {
let serializedError = String(e);
if (serializedError === objectObject) {
try {
serializedError = JSON.stringify(e);
}
catch { }
}
this.logger.debug(`error thrown while processing ${logAttributes}: ${serializedError}`);
const { requeueParams } = this.getOptionsByPattern(pattern);
// skipping coverage as it will make test too long with default values
/* istanbul ignore next */
if (!requeueParams)
message.requeue();
else if (Array.isArray(requeueParams))
message.requeue(...requeueParams);
else
message.requeue(...requeueParams(message, pattern));
this.logger.debug(`${logAttributes} requeued`);
}
finally {
this.logger.verbose(`${logAttributes} processed ${success ? 'successfully' : 'with error'}`);
this.handlingMessagesWG.done();
}
};
}
}
exports.NSQStrategy = NSQStrategy;
const objectObject = {}.toString();
//# sourceMappingURL=server.js.map