UNPKG

nats-micro

Version:

NATS micro compatible extra-lightweight microservice library

186 lines 8.31 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Microservice = void 0; const debug_threads_ns_1 = require("debug-threads-ns"); const events_1 = __importDefault(require("events")); const discovery_js_1 = require("./discovery.js"); const debug_js_1 = require("../debug.js"); const storage_js_1 = require("../decorators/storage.js"); const index_js_1 = require("../utils/index.js"); const util_1 = require("util"); class Microservice { constructor(broker, config, options) { var _a; this.broker = broker; this.options = options; this.ee = new events_1.default(); // eslint-disable-next-line @typescript-eslint/no-explicit-any this.startedMethods = {}; this.discovery = new discovery_js_1.Discovery(broker, config, { transformConfig: ((_a = this.options) === null || _a === void 0 ? void 0 : _a.noStopMethod) ? undefined : this.addMicroserviceStopToConfig.bind(this), }); } static create(broker, config, options) { return __awaiter(this, void 0, void 0, function* () { const ms = new Microservice(broker, config, options); yield ms.start(); return ms; }); } static createFromClass(broker, target, options) { return __awaiter(this, void 0, void 0, function* () { const config = storage_js_1.storage.getConfig(target); if (!config) throw new Error('Class not found'); for (const method of Object.values(config.methods)) method.handler = method.handler.bind(target); const service = yield Microservice.create(broker, config, options); /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ target['__microservice'] = service; return service; }); } get id() { return Object.freeze(this.discovery.id); } get config() { return Object.freeze(this.discovery.config); } on(event, listener) { if (event === 'close') (0, util_1.deprecate)(() => this.on('stop', listener), 'close is deprecated. Use stop instead'); else this.ee.on(event, listener); } off(event, listener) { if (event === 'close') (0, util_1.deprecate)(() => this.off('stop', listener), 'close is deprecated. Use stop instead'); else this.ee.off(event, listener); } emit(event) { this.ee.emit(event); } addMicroserviceStopToConfig(config) { return Object.assign(Object.assign({}, config), { methods: Object.assign(Object.assign({}, config.methods), { microservice_stop: { handler: this.handleStop.bind(this), metadata: { 'nats.micro.ext.v1.feature': 'microservice_stop', 'nats.micro.ext.v1.feature.params': `{"name":"${config.name}","id":"${this.id}"}`, }, unbalanced: true, local: true, } }) }); } startMethod(name, method) { return __awaiter(this, void 0, void 0, function* () { const methodWrap = (0, index_js_1.wrapMethodSafe)(this.broker, (0, index_js_1.attachThreadContext)(this.discovery.id, this.getProfiledMethodHandler(name, method)), { microservice: this.config.name, method: name, methodConfig: method, }); this.startedMethods[name] = { handler: methodWrap, config: method, }; this.broker.on(this.discovery.getMethodSubject(name, method), methodWrap, method.unbalanced || method.local ? undefined : 'q'); }); } stopMethod(name, method) { return __awaiter(this, void 0, void 0, function* () { this.broker.off(this.discovery.getMethodSubject(name, method), this.startedMethods[name].handler); delete (this.startedMethods[name]); }); } start() { return __awaiter(this, void 0, void 0, function* () { debug_threads_ns_1.threadContext.init(this.discovery.id); const cfg = this.discovery.config; debug_js_1.debug.ms.thread.info(`Starting microservice ${cfg.name}(${Object.keys(cfg.methods).join(',')})`); for (const [name, method] of Object.entries(cfg.methods)) yield this.startMethod(name, method); yield this.discovery.start(); return this; }); } restart() { return __awaiter(this, void 0, void 0, function* () { if (!this.discovery.isStarted) return this.start(); debug_threads_ns_1.threadContext.init(this.discovery.id); const cfg = this.discovery.config; debug_js_1.debug.ms.thread.info(`Restarting microservice ${cfg.name}(${Object.keys(cfg.methods).join(',')})`); for (const [name, method] of Object.entries(this.startedMethods)) yield this.stopMethod(name, method.config); for (const [name, method] of Object.entries(cfg.methods)) yield this.startMethod(name, method); yield this.discovery.publish(); return this; }); } handleStop(_req, res) { return __awaiter(this, void 0, void 0, function* () { yield this.stop(); res.send(undefined); }); } stop() { return __awaiter(this, void 0, void 0, function* () { debug_threads_ns_1.threadContext.init(this.discovery.id); const cfg = this.discovery.config; debug_js_1.debug.ms.thread.info(`Stopping microservice ${cfg.name}(${Object.keys(cfg.methods).join(',')})`); for (const [name, method] of Object.entries(cfg.methods)) yield this.stopMethod(name, method); yield this.discovery.stop(); this.emit('stop'); this.emit('close'); // close is deprecated return this; }); } getProfiledMethodHandler(name, method) { return (req, res) => __awaiter(this, void 0, void 0, function* () { const start = process.hrtime.bigint(); try { if (method.middlewares) for (const middleware of method.middlewares) { yield middleware(req, res); } if (!res.isClosed) { yield method.handler(req, res); if (method.postMiddlewares) for (const middleware of method.postMiddlewares) { yield middleware(req, res); } } res.closeWaiter.catch((err) => { throw err; }); res.closeWaiter.then(() => { const elapsed = process.hrtime.bigint() - start; this.discovery.profileMethod(name, undefined, Number(elapsed)); }); } catch (err) { const elapsed = process.hrtime.bigint() - start; this.discovery.profileMethod(name, (0, index_js_1.errorToString)(err), Number(elapsed)); throw err; } }); } } exports.Microservice = Microservice; //# sourceMappingURL=microservice.js.map