UNPKG

15.8 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _autoBind = _interopRequireDefault(require("auto-bind"));
9
10var _System = _interopRequireDefault(require("./System"));
11
12var _Module = _interopRequireDefault(require("./Module"));
13
14var _asyncUtils = require("./asyncUtils");
15
16var _consts = require("./consts");
17
18function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
20function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
21
22const {
23 MODULE_NAME,
24 log,
25 warn,
26 error,
27 noteGauge,
28 noteCount,
29 noteTimer,
30 trackOp
31} = new _Module.default(__filename); // eslint-disable-line no-unused-vars
32
33class Execution {
34 /**
35 * An async function that is called AFTER a termination has accured and infra resources were released,
36 * This handler is called after infra resources were flushed, so it should avoid using them.
37 */
38 constructor(options) {
39 _defineProperty(this, "_options", void 0);
40
41 _defineProperty(this, "_startTimeMS", void 0);
42
43 _defineProperty(this, "_endTimeMS", void 0);
44
45 _defineProperty(this, "_terminating", false);
46
47 _defineProperty(this, "_onTerminateHandlers", []);
48
49 _defineProperty(this, "terminationHandler", void 0);
50
51 this._options = options || {
52 dontTerminateOnCompletion: false
53 };
54 (0, _autoBind.default)(this);
55 }
56
57 async run(runFunc) {
58 try {
59 noteCount(`execution.start`); // Catches ctrl+c and PM2 shutdown
60
61 process.on('SIGINT', async () => await this._terminate(new Error('SIGINT')));
62
63 if (_System.default.getConfig().trackVitalsIntervalMS) {
64 this._trackVitals();
65 }
66
67 this._startTimeMS = Date.now();
68 log('Execution started');
69 const returnValue = await runFunc();
70
71 if (!this._options.dontTerminateOnCompletion) {
72 await this._terminate(null, returnValue);
73 }
74 } catch (err) {
75 await this._terminate(err);
76 }
77 }
78 /**
79 * Allows adding an async function that is called BEFORE a termination has accured.
80 * @param {*} terminationHandler
81 */
82
83
84 addOnTerminateHandler(onTerminateHandler) {
85 this._onTerminateHandlers.push(onTerminateHandler);
86 }
87
88 async _trackVitals() {
89 while (!this._terminating) {
90 try {
91 const used = process.memoryUsage();
92
93 for (const key in used) {
94 noteGauge(`memory.${key}MB`, Math.round(used[key] / 1024 / 1024 * 100) / 100);
95 }
96
97 await (0, _asyncUtils.sleep)(_System.default.getConfig().trackVitalsIntervalMS || 10 * _consts.SECOND_MS);
98 } catch (err) {
99 error('Failed to track vitals', {
100 err
101 });
102 await (0, _asyncUtils.sleep)(1 * _consts.MINUTE_MS);
103 }
104 }
105 }
106
107 async _terminate(terminationError, data) {
108 if (this._terminating) return;
109 this._terminating = true;
110 this._endTimeMS = Date.now(); // $FlowIgnore
111
112 const durationMS = this._endTimeMS - this._startTimeMS;
113
114 if (terminationError == null) {
115 await noteCount(`execution.succeed`);
116 await noteTimer('execution.succeed_duration', durationMS);
117 log('Execution ended successfully', {
118 durationMS
119 });
120 } else if (terminationError.message === 'SIGINT') {
121 await noteCount(`execution.terminate`);
122 await noteTimer('execution.terminate_duration', durationMS);
123 warn('Execution terminated by SIGINT signal, terminating...', {
124 durationMS
125 });
126 } else {
127 await noteCount(`execution.fail`);
128 await noteTimer('execution.fail_duration', durationMS);
129 error('Execution threw an unhandled exception, terminating...', {
130 durationMS,
131 err: terminationError
132 });
133 }
134
135 await noteCount('execution.end');
136 await noteTimer('execution.end_duration', durationMS); // onTerniate handlers
137
138 for (const onTerminateHandler of this._onTerminateHandlers) {
139 try {
140 await onTerminateHandler(terminationError, data);
141 } catch (err) {
142 error('one of the onTerminate handlers threw an error', {
143 err
144 });
145 }
146 }
147
148 await _System.default.flush(); // NOTE: logging or tracking behind this point are not guaranteed to be transmitted
149
150 if (!this.terminationHandler) {
151 process.exit(terminationError == null ? 0 : 1);
152 } else {
153 // terminationHandler
154 try {
155 await this.terminationHandler(terminationError, data);
156 } catch (err) {
157 error('terminationHandler threw an error', {
158 err
159 });
160 await _System.default.flush();
161 process.exit(1);
162 }
163 }
164 }
165
166}
167
168exports.default = Execution;
169//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9FeGVjdXRpb24uanMiXSwibmFtZXMiOlsiTU9EVUxFX05BTUUiLCJsb2ciLCJ3YXJuIiwiZXJyb3IiLCJub3RlR2F1Z2UiLCJub3RlQ291bnQiLCJub3RlVGltZXIiLCJ0cmFja09wIiwiTW9kdWxlIiwiX19maWxlbmFtZSIsIkV4ZWN1dGlvbiIsImNvbnN0cnVjdG9yIiwib3B0aW9ucyIsIl9vcHRpb25zIiwiZG9udFRlcm1pbmF0ZU9uQ29tcGxldGlvbiIsInJ1biIsInJ1bkZ1bmMiLCJwcm9jZXNzIiwib24iLCJfdGVybWluYXRlIiwiRXJyb3IiLCJTeXN0ZW0iLCJnZXRDb25maWciLCJ0cmFja1ZpdGFsc0ludGVydmFsTVMiLCJfdHJhY2tWaXRhbHMiLCJfc3RhcnRUaW1lTVMiLCJEYXRlIiwibm93IiwicmV0dXJuVmFsdWUiLCJlcnIiLCJhZGRPblRlcm1pbmF0ZUhhbmRsZXIiLCJvblRlcm1pbmF0ZUhhbmRsZXIiLCJfb25UZXJtaW5hdGVIYW5kbGVycyIsInB1c2giLCJfdGVybWluYXRpbmciLCJ1c2VkIiwibWVtb3J5VXNhZ2UiLCJrZXkiLCJNYXRoIiwicm91bmQiLCJTRUNPTkRfTVMiLCJNSU5VVEVfTVMiLCJ0ZXJtaW5hdGlvbkVycm9yIiwiZGF0YSIsIl9lbmRUaW1lTVMiLCJkdXJhdGlvbk1TIiwibWVzc2FnZSIsImZsdXNoIiwidGVybWluYXRpb25IYW5kbGVyIiwiZXhpdCJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUVBOztBQUVBOztBQUNBOztBQUNBOztBQUNBOzs7Ozs7QUFFQSxNQUFNO0FBQUVBLEVBQUFBLFdBQUY7QUFBZUMsRUFBQUEsR0FBZjtBQUFvQkMsRUFBQUEsSUFBcEI7QUFBMEJDLEVBQUFBLEtBQTFCO0FBQWlDQyxFQUFBQSxTQUFqQztBQUE0Q0MsRUFBQUEsU0FBNUM7QUFBdURDLEVBQUFBLFNBQXZEO0FBQWtFQyxFQUFBQTtBQUFsRSxJQUE4RSxJQUFJQyxlQUFKLENBQVdDLFVBQVgsQ0FBcEYsQyxDQUEy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QUFMLENBQXdCTixnQkFBeEIsRUFBMENDLElBQTFDLENBQU47QUFDRCxPQUZELENBRUUsT0FBT2QsR0FBUCxFQUFZO0FBQ1oxQixRQUFBQSxLQUFLLENBQUMsbUNBQUQsRUFBc0M7QUFBRTBCLFVBQUFBO0FBQUYsU0FBdEMsQ0FBTDtBQUNBLGNBQU1SLGdCQUFPMEIsS0FBUCxFQUFOO0FBQ0E5QixRQUFBQSxPQUFPLENBQUNnQyxJQUFSLENBQWEsQ0FBYjtBQUNEO0FBQ0Y7QUFDRjs7QUF4SCtCIiwic291cmNlc0NvbnRlbnQiOlsiLy9AZmxvd1xuXG5pbXBvcnQgYXV0b0JpbmQgZnJvbSAnYXV0by1iaW5kJ1xuXG5pbXBvcnQgU3lzdGVtIGZyb20gJy4vU3lzdGVtJ1xuaW1wb3J0IE1vZHVsZSBmcm9tICcuL01vZHVsZSdcbmltcG9ydCB7IHNsZWVwIH0gZnJvbSAnLi9hc3luY1V0aWxzJ1xuaW1wb3J0IHsgU0VDT05EX01TLCBNSU5VVEVfTVMgfSBmcm9tICcuL2NvbnN0cydcblxuY29uc3QgeyBNT0RVTEVfTkFNRSwgbG9nLCB3YXJuLCBlcnJvciwgbm90ZUdhdWdlLCBub3RlQ291bnQsIG5vdGVUaW1lciwgdHJhY2tPcCB9ID0gbmV3IE1vZHVsZShfX2ZpbGVuYW1lKSAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG5cbnR5cGUgRXhlY3V0aW9uT3B0aW9ucyA9IHt8XG4gIGRvbnRUZXJtaW5hdGVPbkNvbXBsZXRpb24/OiA/Ym9vbGVhbiwgLy8gVXNlZCBmb3IgY2FzZXMgd2hlcmUgY29kZSByZXR1cm5zIGJ1dCBzb21lIGNhbGxiYWNrcyBzdGlsbCBrZWVwIHRoZSBwcm9jZXNzIGFsaXZlIChsaWtlIHdlYiBzZXJ2ZXIpXG58fVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBFeGVjdXRpb248VD4ge1xuXG4gIF9vcHRpb25zOiBFeGVjdXRpb25PcHRpb25zXG4gIF9zdGFydFRpbWVNUzogP251bWJlclxuICBfZW5kVGltZU1TOiA/bnVtYmVyXG4gIF90ZXJtaW5hdGluZzogYm9vbGVhbiA9IGZhbHNlXG4gIF9vblRlcm1pbmF0ZUhhbmRsZXJzOiBBcnJheTwoZXJyOiA/RXJyb3IsIGRhdGE6ID9UKSA9PiBQcm9taXNlPHZvaWQ+PiA9IFtdXG5cbiAgLyoqXG4gICogQW4gYXN5bmMgZnVuY3Rpb24gdGhhdCBpcyBjYWxsZWQgQUZURVIgYSB0ZXJtaW5hdGlvbiBoYXMgYWNjdXJlZCBhbmQgaW5mcmEgcmVzb3VyY2VzIHdlcmUgcmVsZWFzZWQsXG4gICogVGhpcyBoYW5kbGVyIGlzIGNhbGxlZCBhZnRlciBpbmZyYSByZXNvdXJjZXMgd2VyZSBmbHVzaGVkLCBzbyBpdCBzaG91bGQgYXZvaWQgdXNpbmcgdGhlbS5cbiAgKi9cbiAgdGVybWluYXRpb25IYW5kbGVyOiA/KGVycjogP0Vycm9yLCBkYXRhOiA/VCkgPT4gUHJvbWlzZTx2b2lkPlxuXG5cbiAgY29uc3RydWN0b3Iob3B0aW9ucz86ID9FeGVjdXRpb25PcHRpb25zKSB7XG4gICAgdGhpcy5fb3B0aW9ucyA9IG9wdGlvbnMgfHwge1xuICAgICAgZG9udFRlcm1pbmF0ZU9uQ29tcGxldGlvbjogZmFsc2UsXG4gICAgfVxuXG4gICAgYXV0b0JpbmQodGhpcylcbiAgfVxuXG5cbiAgYXN5bmMgcnVuKHJ1bkZ1bmM6ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgbm90ZUNvdW50KGBleGVjdXRpb24uc3RhcnRgKVxuXG4gICAgICAvLyBDYXRjaGVzIGN0cmwrYyBhbmQgUE0yIHNodXRkb3duXG4gICAgICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAoKSA9PiBhd2FpdCB0aGlzLl90ZXJtaW5hdGUobmV3IEVycm9yKCdTSUdJTlQnKSkpXG5cbiAgICAgIGlmIChTeXN0ZW0uZ2V0Q29uZmlnKCkudHJhY2tWaXRhbHNJbnRlcnZhbE1TKSB7XG4gICAgICAgIHRoaXMuX3RyYWNrVml0YWxzKClcbiAgICAgIH1cblxuICAgICAgdGhpcy5fc3RhcnRUaW1lTVMgPSBEYXRlLm5vdygpXG4gICAgICBsb2coJ0V4ZWN1dGlvbiBzdGFydGVkJylcbiAgICAgIGNvbnN0IHJldHVyblZhbHVlID0gYXdhaXQgcnVuRnVuYygpXG5cbiAgICAgIGlmICghdGhpcy5fb3B0aW9ucy5kb250VGVybWluYXRlT25Db21wbGV0aW9uKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3Rlcm1pbmF0ZShudWxsLCByZXR1cm5WYWx1ZSlcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGF3YWl0IHRoaXMuX3Rlcm1pbmF0ZShlcnIpXG4gICAgfSBcbiAgfVxuXG4gIC8qKlxuICAqIEFsbG93cyBhZGRpbmcgYW4gYXN5bmMgZnVuY3Rpb24gdGhhdCBpcyBjYWxsZWQgQkVGT1JFIGEgdGVybWluYXRpb24gaGFzIGFjY3VyZWQuXG4gICogQHBhcmFtIHsqfSB0ZXJtaW5hdGlvbkhhbmRsZXJcbiAgKi9cbiAgYWRkT25UZXJtaW5hdGVIYW5kbGVyKG9uVGVybWluYXRlSGFuZGxlcjogKGVycjogP0Vycm9yLCBkYXRhOiA/VCkgPT4gUHJvbWlzZTx2b2lkPik6IHZvaWQge1xuICAgIHRoaXMuX29uVGVybWluYXRlSGFuZGxlcnMucHVzaChvblRlcm1pbmF0ZUhhbmRsZXIpXG4gIH1cblxuXG4gIGFzeW5jIF90cmFja1ZpdGFscygpIHtcbiAgICB3aGlsZSAoIXRoaXMuX3Rlcm1pbmF0aW5nKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB1c2VkID0gcHJvY2Vzcy5tZW1vcnlVc2FnZSgpXG4gICAgICAgIGZvciAoY29uc3Qga2V5IGluIHVzZWQpIHtcbiAgICAgICAgICBub3RlR2F1Z2UoYG1lbW9yeS4ke2tleX1NQmAsIE1hdGgucm91bmQodXNlZFtrZXldIC8gMTAyNCAvIDEwMjQgKiAxMDApIC8gMTAwKVxuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHNsZWVwKFN5c3RlbS5nZXRDb25maWcoKS50cmFja1ZpdGFsc0ludGVydmFsTVMgfHwgMTAgKiBTRUNPTkRfTVMpXG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgZXJyb3IoJ0ZhaWxlZCB0byB0cmFjayB2aXRhbHMnLCB7IGVyciB9KVxuICAgICAgICBhd2FpdCBzbGVlcCgxICogTUlOVVRFX01TKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIF90ZXJtaW5hdGUodGVybWluYXRpb25FcnJvcjogP0Vycm9yLCBkYXRhOiA/VCkge1xuICAgIGlmICh0aGlzLl90ZXJtaW5hdGluZylcbiAgICAgIHJldHVyblxuICAgIHRoaXMuX3Rlcm1pbmF0aW5nID0gdHJ1ZVxuICAgIFxuICAgIHRoaXMuX2VuZFRpbWVNUyA9IERhdGUubm93KClcbiAgICAvLyAkRmxvd0lnbm9yZVxuICAgIGNvbnN0IGR1cmF0aW9uTVMgPSB0aGlzLl9lbmRUaW1lTVMgLSB0aGlzLl9zdGFydFRpbWVNU1xuXG4gICAgaWYgKHRlcm1pbmF0aW9uRXJyb3IgPT0gbnVsbCkge1xuICAgICAgYXdhaXQgbm90ZUNvdW50KGBleGVjdXRpb24uc3VjY2VlZGApXG4gICAgICBhd2FpdCBub3RlVGltZXIoJ2V4ZWN1dGlvbi5zdWNjZWVkX2R1cmF0aW9uJywgZHVyYXRpb25NUylcbiAgICAgIGxvZygnRXhlY3V0aW9uIGVuZGVkIHN1Y2Nlc3NmdWxseScsIHsgZHVyYXRpb25NUyB9KVxuICAgIH0gZWxzZSBpZiAodGVybWluYXRpb25FcnJvci5tZXNzYWdlID09PSAnU0lHSU5UJykge1xuICAgICAgYXdhaXQgbm90ZUNvdW50KGBleGVjdXRpb24udGVybWluYXRlYClcbiAgICAgIGF3YWl0IG5vdGVUaW1lcignZXhlY3V0aW9uLnRlcm1pbmF0ZV9kdXJhdGlvbicsIGR1cmF0aW9uTVMpXG4gICAgICB3YXJuKCdFeGVjdXRpb24gdGVybWluYXRlZCBieSBTSUdJTlQgc2lnbmFsLCB0ZXJtaW5hdGluZy4uLicsIHsgZHVyYXRpb25NUyB9KVxuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCBub3RlQ291bnQoYGV4ZWN1dGlvbi5mYWlsYClcbiAgICAgIGF3YWl0IG5vdGVUaW1lcignZXhlY3V0aW9uLmZhaWxfZHVyYXRpb24nLCBkdXJhdGlvbk1TKVxuICAgICAgZXJyb3IoJ0V4ZWN1dGlvbiB0aHJldyBhbiB1bmhhbmRsZWQgZXhjZXB0aW9uLCB0ZXJtaW5hdGluZy4uLicsIHsgZHVyYXRpb25NUywgZXJyOiB0ZXJtaW5hdGlvbkVycm9yIH0pXG4gICAgfVxuICAgIGF3YWl0IG5vdGVDb3VudCgnZXhlY3V0aW9uLmVuZCcpXG4gICAgYXdhaXQgbm90ZVRpbWVyKCdleGVjdXRpb24uZW5kX2R1cmF0aW9uJywgZHVyYXRpb25NUylcblxuICAgIC8vIG9uVGVybmlhdGUgaGFuZGxlcnNcbiAgICBmb3IgKGNvbnN0IG9uVGVybWluYXRlSGFuZGxlciBvZiB0aGlzLl9vblRlcm1pbmF0ZUhhbmRsZXJzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBvblRlcm1pbmF0ZUhhbmRsZXIodGVybWluYXRpb25FcnJvciwgZGF0YSlcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBlcnJvcignb25lIG9mIHRoZSBvblRlcm1pbmF0ZSBoYW5kbGVycyB0aHJldyBhbiBlcnJvcicsIHsgZXJyIH0pXG4gICAgICB9XG4gICAgfVxuXG4gICAgYXdhaXQgU3lzdGVtLmZsdXNoKClcbiAgICAvLyBOT1RFOiBsb2dnaW5nIG9yIHRyYWNraW5nIGJlaGluZCB0aGlzIHBvaW50IGFyZSBub3QgZ3VhcmFudGVlZCB0byBiZSB0cmFuc21pdHRlZFxuXG4gICAgaWYgKCF0aGlzLnRlcm1pbmF0aW9uSGFuZGxlcikge1xuICAgICAgcHJvY2Vzcy5leGl0KHRlcm1pbmF0aW9uRXJyb3IgPT0gbnVsbCA/IDAgOiAxKVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyB0ZXJtaW5hdGlvbkhhbmRsZXJcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMudGVybWluYXRpb25IYW5kbGVyKHRlcm1pbmF0aW9uRXJyb3IsIGRhdGEpXG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgZXJyb3IoJ3Rlcm1pbmF0aW9uSGFuZGxlciB0aHJldyBhbiBlcnJvcicsIHsgZXJyIH0pXG4gICAgICAgIGF3YWl0IFN5c3RlbS5mbHVzaCgpXG4gICAgICAgIHByb2Nlc3MuZXhpdCgxKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG59XG4iXX0=
\No newline at end of file