nats-micro
Version:
NATS micro compatible extra-lightweight microservice library
186 lines • 8.31 kB
JavaScript
"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