@yolo-croket-dev/core 1.4.53-slowquery.1 → 1.4.53-slowquery.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/interceptors/rpc.interceptor.js +45 -6
- package/modules/graceful-shutdown/graceful-shutdown.module.js +1 -0
- package/modules/graceful-shutdown/graceful-shutdown.rmq.d.ts +20 -0
- package/modules/graceful-shutdown/graceful-shutdown.rmq.js +59 -0
- package/modules/graceful-shutdown/graceful-shutdown.service.d.ts +13 -4
- package/modules/graceful-shutdown/graceful-shutdown.service.js +31 -8
- package/package.json +1 -1
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
2
18
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
19
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
20
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
21
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
22
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
23
|
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
25
|
+
if (mod && mod.__esModule) return mod;
|
|
26
|
+
var result = {};
|
|
27
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
28
|
+
__setModuleDefault(result, mod);
|
|
29
|
+
return result;
|
|
30
|
+
};
|
|
8
31
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
32
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
33
|
};
|
|
@@ -15,10 +38,13 @@ const common_1 = require("@nestjs/common");
|
|
|
15
38
|
const core_1 = require("@nestjs/core");
|
|
16
39
|
const rxjs_1 = require("rxjs");
|
|
17
40
|
const operators_1 = require("rxjs/operators");
|
|
41
|
+
const msa_logger_1 = __importStar(require("@yolo-croket-dev/msa-logger"));
|
|
18
42
|
// import Logger from '@yolo-croket-dev/logger';
|
|
19
43
|
const functions_1 = require("../functions");
|
|
20
44
|
const exceptions_1 = require("../exceptions");
|
|
21
45
|
const graceful_shutdown_service_1 = require("../modules/graceful-shutdown/graceful-shutdown.service");
|
|
46
|
+
// const logger = Logger.createLogger('RPCInterceptor');
|
|
47
|
+
const msaLogger = new msa_logger_1.default(msa_logger_1.ServerTypeEnum.SERVICE);
|
|
22
48
|
// const MAX_CUT_LENGTH = 500;
|
|
23
49
|
const MAX_LENGTH = 300;
|
|
24
50
|
let RPCInterceptor = class RPCInterceptor {
|
|
@@ -108,7 +134,7 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
108
134
|
// return data;
|
|
109
135
|
// }
|
|
110
136
|
async intercept(context, next) {
|
|
111
|
-
var _a;
|
|
137
|
+
var _a, _b;
|
|
112
138
|
const options = this.reflector.get('rpcInterceptorScope', context.getHandler());
|
|
113
139
|
const args = context.getArgs();
|
|
114
140
|
const arg = args[0];
|
|
@@ -120,13 +146,25 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
120
146
|
// const traceId = content.data.param ? content.data.param.traceId : null;
|
|
121
147
|
const isInternal = content.data.param ? content.data.param.isInternal : false;
|
|
122
148
|
const isAdmin = content.data.param ? content.data.param.isAdmin : false;
|
|
123
|
-
// const method = content.pattern;
|
|
124
149
|
const reDeliveryCount = Number(message.properties.headers['x-delivery-count']) || 0; /** 몇번 재전달되었는지 */
|
|
125
150
|
const staticRetryCount = Number(options === null || options === void 0 ? void 0 : options.messageRetryCount) || 0; /** 최대 재시도 갯수 */
|
|
151
|
+
const method = content.pattern;
|
|
152
|
+
const correlationId = message.properties.correlationId;
|
|
153
|
+
const execInterceptor = {
|
|
154
|
+
method,
|
|
155
|
+
traceId: ((_a = content.data.param) === null || _a === void 0 ? void 0 : _a.traceId) || '-',
|
|
156
|
+
correlationId,
|
|
157
|
+
};
|
|
126
158
|
// const logParam = {
|
|
127
159
|
// traceId,
|
|
128
160
|
// method,
|
|
129
161
|
// };
|
|
162
|
+
/** consume 메시지 전부 cancel */
|
|
163
|
+
if (this.gracefulShutdownService.isApplicationExit) {
|
|
164
|
+
msaLogger.debug('RPCInterceptor isApplicationExit called', { traceId: 'IS_APPLICATION_EXIT' });
|
|
165
|
+
channel.cancel(message.fields.consumerTag);
|
|
166
|
+
return new rxjs_1.Observable();
|
|
167
|
+
}
|
|
130
168
|
if (!staticRetryCount && reDeliveryCount > 0) {
|
|
131
169
|
channel.sendToQueue(message.properties.replyTo, Buffer.from(JSON.stringify({
|
|
132
170
|
isError: true,
|
|
@@ -205,7 +243,7 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
205
243
|
};
|
|
206
244
|
localErrorProcessor = localErrorProcessor.bind(this);
|
|
207
245
|
/** 파일 객체 처리 */
|
|
208
|
-
(0, functions_1.reWriteFileValue)((
|
|
246
|
+
(0, functions_1.reWriteFileValue)((_b = content === null || content === void 0 ? void 0 : content.data) === null || _b === void 0 ? void 0 : _b.file);
|
|
209
247
|
if (options) {
|
|
210
248
|
if (options.maxLengthKeys && options.maxLengthKeys.length) {
|
|
211
249
|
for (const key of options.maxLengthKeys) {
|
|
@@ -234,11 +272,12 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
234
272
|
else {
|
|
235
273
|
// logger.debug(`=> (${traceId}): ${JSON.stringify(this.keyCutter(JSON.stringify(content)))}`);
|
|
236
274
|
}
|
|
237
|
-
this.gracefulShutdownService.
|
|
275
|
+
this.gracefulShutdownService.pushActiveInterceptors(execInterceptor);
|
|
238
276
|
// eslint-disable-next-line consistent-return
|
|
239
277
|
return next
|
|
240
278
|
.handle()
|
|
241
|
-
.pipe((0, operators_1.
|
|
279
|
+
.pipe((0, operators_1.timeout)(1000 * 60 * 30), // 30분 타임아웃
|
|
280
|
+
(0, operators_1.tap)({
|
|
242
281
|
next: async (val) => {
|
|
243
282
|
val.isError = false;
|
|
244
283
|
// const duration = Date.now() - now;
|
|
@@ -258,7 +297,7 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
258
297
|
},
|
|
259
298
|
error: localErrorProcessor,
|
|
260
299
|
}), (0, operators_1.finalize)(() => {
|
|
261
|
-
this.gracefulShutdownService.
|
|
300
|
+
this.gracefulShutdownService.popActiveInterceptors(execInterceptor);
|
|
262
301
|
}));
|
|
263
302
|
}
|
|
264
303
|
};
|
|
@@ -13,6 +13,7 @@ let GracefulShutdownModule = class GracefulShutdownModule {
|
|
|
13
13
|
};
|
|
14
14
|
exports.GracefulShutdownModule = GracefulShutdownModule;
|
|
15
15
|
exports.GracefulShutdownModule = GracefulShutdownModule = __decorate([
|
|
16
|
+
(0, common_1.Global)(),
|
|
16
17
|
(0, common_1.Module)({
|
|
17
18
|
providers: [graceful_shutdown_service_1.GracefulShutdownService],
|
|
18
19
|
exports: [graceful_shutdown_service_1.GracefulShutdownService],
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { RmqOptions, ServerRMQ } from '@nestjs/microservices';
|
|
2
|
+
import { Channel } from 'amqp-connection-manager';
|
|
3
|
+
import { ConsumeMessage } from 'amqplib';
|
|
4
|
+
export type GracefulRmqOptions = RmqOptions['options'] & {
|
|
5
|
+
waitingEndingHandlersTimeoutMs?: number;
|
|
6
|
+
waitingEndingHandlersIntervalMs?: number;
|
|
7
|
+
};
|
|
8
|
+
export declare class GracefulServerRMQ extends ServerRMQ {
|
|
9
|
+
protected readonly options: GracefulRmqOptions;
|
|
10
|
+
protected runningMessages: number;
|
|
11
|
+
protected closing: boolean;
|
|
12
|
+
protected consumerTag: string | null;
|
|
13
|
+
protected readonly waitingEndingHandlersTimeoutMs: number;
|
|
14
|
+
protected readonly waitingEndingHandlersIntervalMs: number;
|
|
15
|
+
constructor(options: GracefulRmqOptions);
|
|
16
|
+
setupChannel(channel: Channel, callback: () => void): Promise<void>;
|
|
17
|
+
protected waitingHandlers(): Promise<void>;
|
|
18
|
+
handleMessage(message: ConsumeMessage, channel: Channel): Promise<void>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GracefulServerRMQ = void 0;
|
|
4
|
+
const microservices_1 = require("@nestjs/microservices");
|
|
5
|
+
const node_util_1 = require("node:util");
|
|
6
|
+
const sleep = (0, node_util_1.promisify)(setTimeout);
|
|
7
|
+
const RMQ_DEFAULT_WAITING_ENDING_HANDLERS_TIMEOUT_MS = 5000;
|
|
8
|
+
const RMQ_DEFAULT_WAITING_ENDING_HANDLERS_INTERVAL_MS = 500;
|
|
9
|
+
class GracefulServerRMQ extends microservices_1.ServerRMQ {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super(options);
|
|
12
|
+
this.options = options;
|
|
13
|
+
this.runningMessages = 0;
|
|
14
|
+
this.closing = false;
|
|
15
|
+
this.consumerTag = null;
|
|
16
|
+
this.waitingEndingHandlersTimeoutMs = this.getOptionsProp(this.options, 'waitingEndingHandlersTimeoutMs')
|
|
17
|
+
|| RMQ_DEFAULT_WAITING_ENDING_HANDLERS_TIMEOUT_MS;
|
|
18
|
+
this.waitingEndingHandlersIntervalMs = this.getOptionsProp(this.options, 'waitingEndingHandlersIntervalMs')
|
|
19
|
+
|| RMQ_DEFAULT_WAITING_ENDING_HANDLERS_INTERVAL_MS;
|
|
20
|
+
}
|
|
21
|
+
async setupChannel(channel, callback) {
|
|
22
|
+
if (this.closing) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!this.queueOptions.noAssert) {
|
|
26
|
+
await channel.assertQueue(this.queue, this.queueOptions);
|
|
27
|
+
}
|
|
28
|
+
await channel.prefetch(this.prefetchCount, this.isGlobalPrefetchCount);
|
|
29
|
+
const { consumerTag } = await channel.consume(this.queue, (msg) => this.handleMessage(msg, channel), { noAck: false });
|
|
30
|
+
this.consumerTag = consumerTag;
|
|
31
|
+
callback();
|
|
32
|
+
}
|
|
33
|
+
async waitingHandlers() {
|
|
34
|
+
while (this.runningMessages > 0) {
|
|
35
|
+
await sleep(this.waitingEndingHandlersIntervalMs);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async handleMessage(message, channel) {
|
|
39
|
+
this.runningMessages += 1;
|
|
40
|
+
return super.handleMessage(message, channel).finally(() => {
|
|
41
|
+
this.runningMessages -= 1;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async close() {
|
|
45
|
+
this.closing = true;
|
|
46
|
+
if (this.channel) {
|
|
47
|
+
await this.channel.removeSetup(undefined, (channel) => channel.cancel(this.consumerTag));
|
|
48
|
+
}
|
|
49
|
+
this.consumerTag = null;
|
|
50
|
+
await Promise.race([
|
|
51
|
+
this.waitingHandlers(),
|
|
52
|
+
this.waitingEndingHandlersTimeoutMs > 0
|
|
53
|
+
&& sleep(this.waitingEndingHandlersTimeoutMs),
|
|
54
|
+
]);
|
|
55
|
+
this.runningMessages = 0;
|
|
56
|
+
super.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.GracefulServerRMQ = GracefulServerRMQ;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import { OnApplicationShutdown } from '@nestjs/common';
|
|
2
|
-
|
|
1
|
+
import { OnApplicationShutdown, OnModuleDestroy, OnApplicationBootstrap } from '@nestjs/common';
|
|
2
|
+
interface GracefulExecInterceptor {
|
|
3
|
+
method: string;
|
|
4
|
+
traceId?: string;
|
|
5
|
+
correlationId: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class GracefulShutdownService implements OnApplicationShutdown, OnModuleDestroy, OnApplicationBootstrap {
|
|
3
8
|
private activeInterceptors;
|
|
4
|
-
|
|
5
|
-
|
|
9
|
+
isApplicationExit: boolean;
|
|
10
|
+
onApplicationBootstrap(): void;
|
|
11
|
+
pushActiveInterceptors(execInterceptor: GracefulExecInterceptor): void;
|
|
12
|
+
popActiveInterceptors(execInterceptor: GracefulExecInterceptor): void;
|
|
6
13
|
onApplicationShutdown(signal?: string): Promise<void>;
|
|
14
|
+
onModuleDestroy(): Promise<void>;
|
|
7
15
|
}
|
|
16
|
+
export {};
|
|
@@ -35,19 +35,42 @@ const msa_logger_1 = __importStar(require("@yolo-croket-dev/msa-logger"));
|
|
|
35
35
|
const msaLogger = new msa_logger_1.default(msa_logger_1.ServerTypeEnum.SERVICE);
|
|
36
36
|
let GracefulShutdownService = class GracefulShutdownService {
|
|
37
37
|
constructor() {
|
|
38
|
-
this.activeInterceptors =
|
|
38
|
+
this.activeInterceptors = [];
|
|
39
|
+
this.isApplicationExit = false;
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
-
this.activeInterceptors
|
|
41
|
+
onApplicationBootstrap() {
|
|
42
|
+
this.activeInterceptors = [];
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
this.activeInterceptors
|
|
44
|
+
pushActiveInterceptors(execInterceptor) {
|
|
45
|
+
this.activeInterceptors.push(execInterceptor);
|
|
46
|
+
}
|
|
47
|
+
popActiveInterceptors(execInterceptor) {
|
|
48
|
+
// eslint-disable-next-line max-len
|
|
49
|
+
this.activeInterceptors = this.activeInterceptors.filter((item) => item.method === execInterceptor.method && item.traceId === execInterceptor.traceId && item.correlationId === execInterceptor.correlationId);
|
|
45
50
|
}
|
|
46
51
|
async onApplicationShutdown(signal) {
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
console.debug(`GracefulShutdownService.onApplicationShutdown signal=${signal}`, { traceId: 'ON_APPLICATION_SHUTDOWN' });
|
|
53
|
+
msaLogger.debug(`GracefulShutdownService.onApplicationShutdown signal=${signal}`, { traceId: 'ON_APPLICATION_SHUTDOWN' });
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
async onModuleDestroy() {
|
|
57
|
+
this.isApplicationExit = true;
|
|
58
|
+
msaLogger.debug('GracefulShutdownService.onModuleDestroy', { traceId: 'ON_MODULE_DESTROY' });
|
|
59
|
+
// eslint-disable-next-line max-len
|
|
60
|
+
msaLogger.debug('GracefulShutdownService.onModuleDestroy activeInterceptors', { traceId: 'ON_MODULE_DESTROY' }, { activeInterceptors: this.activeInterceptors });
|
|
61
|
+
// eslint-disable-next-line max-len
|
|
62
|
+
console.debug('GracefulShutdownService.onModuleDestroy activeInterceptors', { traceId: 'ON_MODULE_DESTROY' }, { activeInterceptors: this.activeInterceptors });
|
|
63
|
+
let prevExecInterceptorCount = 0;
|
|
64
|
+
while (this.activeInterceptors.length) {
|
|
65
|
+
if (prevExecInterceptorCount !== this.activeInterceptors.length) {
|
|
66
|
+
prevExecInterceptorCount = this.activeInterceptors.length;
|
|
67
|
+
// eslint-disable-next-line max-len
|
|
68
|
+
console.log(`GracefulShutdownService.onModuleDestroy: waiting for ${this.activeInterceptors} interceptors to finish`, { traceId: 'ON_MODULE_DESTROY' }, { activeInterceptors: this.activeInterceptors });
|
|
69
|
+
// eslint-disable-next-line max-len
|
|
70
|
+
msaLogger.debug(`GracefulShutdownService.onModuleDestroy: waiting for ${this.activeInterceptors} interceptors to finish`, { traceId: 'ON_MODULE_DESTROY' }, { activeInterceptors: this.activeInterceptors });
|
|
71
|
+
}
|
|
49
72
|
await new Promise((resolve) => {
|
|
50
|
-
setTimeout(resolve,
|
|
73
|
+
setTimeout(resolve, 1000);
|
|
51
74
|
});
|
|
52
75
|
}
|
|
53
76
|
}
|