@yolo-croket-dev/core 1.7.25-slowquery.1 → 1.7.25-slowquery.11
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.
|
@@ -346,26 +346,16 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
346
346
|
// logger.debug(`=> (${traceId}): ${JSON.stringify(this.keyCutter(JSON.stringify(content)))}`);
|
|
347
347
|
}
|
|
348
348
|
this.gracefulShutdownService.pushActiveInterceptors(execInterceptor);
|
|
349
|
+
const abort$ = (0, rxjs_1.fromEvent)(abortController.signal, 'abort');
|
|
349
350
|
// eslint-disable-next-line consistent-return
|
|
350
351
|
return next
|
|
351
352
|
.handle()
|
|
352
|
-
.pipe(
|
|
353
|
-
// AbortController 신호 감지
|
|
354
|
-
(0, operators_1.takeUntil)(new rxjs_1.Observable(subscriber => {
|
|
355
|
-
const abortHandler = () => {
|
|
356
|
-
subscriber.next();
|
|
357
|
-
subscriber.complete();
|
|
358
|
-
};
|
|
359
|
-
abortController.signal.addEventListener('abort', abortHandler, { once: true });
|
|
360
|
-
// 정리 함수
|
|
361
|
-
return () => {
|
|
362
|
-
abortController.signal.removeEventListener('abort', abortHandler);
|
|
363
|
-
};
|
|
364
|
-
})),
|
|
353
|
+
.pipe((0, operators_1.takeUntil)(abort$),
|
|
365
354
|
// timeout(1000 * 60 * 29), // 30분 타임아웃
|
|
366
|
-
(0, operators_1.timeout)(1000 *
|
|
355
|
+
(0, operators_1.timeout)(1000 * 3), // 30분 타임아웃
|
|
367
356
|
(0, operators_1.tap)({
|
|
368
357
|
next: async (val) => {
|
|
358
|
+
console.log('RPC Interceptor next called');
|
|
369
359
|
val.isError = false;
|
|
370
360
|
// const duration = Date.now() - now;
|
|
371
361
|
// logger.debug(`<= (success:${traceId}): ${val.message}`, {
|
|
@@ -393,7 +383,6 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
393
383
|
if (isTimeoutError) {
|
|
394
384
|
if (abortController) {
|
|
395
385
|
abortController.abort();
|
|
396
|
-
throw new Error('Message aborted due to timeout');
|
|
397
386
|
}
|
|
398
387
|
msaLogger.error('[타임 아웃] 메시지 재전송 처리', { traceId: execInterceptor.traceId }, {
|
|
399
388
|
error: {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
/// <reference types="node" />
|
|
3
1
|
import { RmqOptions, ServerRMQ } from '@nestjs/microservices';
|
|
4
2
|
import { Channel } from 'amqp-connection-manager';
|
|
5
3
|
import { ConsumeMessage } from 'amqplib';
|
|
@@ -14,14 +12,9 @@ export declare class GracefulServerRMQ extends ServerRMQ {
|
|
|
14
12
|
protected consumerTag: string | null;
|
|
15
13
|
protected readonly waitingEndingHandlersTimeoutMs: number;
|
|
16
14
|
protected readonly waitingEndingHandlersIntervalMs: number;
|
|
17
|
-
protected messageAbortControllers: Map<string, AbortController>;
|
|
18
|
-
protected messageTimeouts: Map<string, NodeJS.Timeout>;
|
|
19
15
|
constructor(options: GracefulRmqOptions);
|
|
20
16
|
setupChannel(channel: Channel, callback: () => void): Promise<void>;
|
|
21
17
|
protected waitingHandlers(): Promise<void>;
|
|
22
18
|
handleMessage(message: ConsumeMessage, channel: Channel): Promise<void>;
|
|
23
|
-
private cleanupMessage;
|
|
24
|
-
abortMessage(messageId: string): void;
|
|
25
|
-
abortAllMessages(): void;
|
|
26
19
|
close(): Promise<void>;
|
|
27
20
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.GracefulServerRMQ = void 0;
|
|
4
4
|
const microservices_1 = require("@nestjs/microservices");
|
|
5
5
|
const node_util_1 = require("node:util");
|
|
6
|
+
const abortable_promise_1 = require("@xuchaoqian/abortable-promise");
|
|
6
7
|
const sleep = (0, node_util_1.promisify)(setTimeout);
|
|
7
8
|
const RMQ_DEFAULT_WAITING_ENDING_HANDLERS_TIMEOUT_MS = 5000;
|
|
8
9
|
const RMQ_DEFAULT_WAITING_ENDING_HANDLERS_INTERVAL_MS = 500;
|
|
@@ -15,10 +16,6 @@ class GracefulServerRMQ extends microservices_1.ServerRMQ {
|
|
|
15
16
|
this.runningMessages = 0;
|
|
16
17
|
this.closing = false;
|
|
17
18
|
this.consumerTag = null;
|
|
18
|
-
// 메시지별 AbortController 관리
|
|
19
|
-
this.messageAbortControllers = new Map();
|
|
20
|
-
// eslint-disable-next-line no-undef
|
|
21
|
-
this.messageTimeouts = new Map();
|
|
22
19
|
this.waitingEndingHandlersTimeoutMs = this.getOptionsProp(this.options, 'waitingEndingHandlersTimeoutMs')
|
|
23
20
|
|| RMQ_DEFAULT_WAITING_ENDING_HANDLERS_TIMEOUT_MS;
|
|
24
21
|
this.waitingEndingHandlersIntervalMs = this.getOptionsProp(this.options, 'waitingEndingHandlersIntervalMs')
|
|
@@ -45,14 +42,12 @@ class GracefulServerRMQ extends microservices_1.ServerRMQ {
|
|
|
45
42
|
const messageId = message.properties.messageId || message.properties.correlationId || `msg_${Date.now()}_${Math.random()}`;
|
|
46
43
|
// AbortController 생성
|
|
47
44
|
const abortController = new AbortController();
|
|
48
|
-
this.messageAbortControllers.set(messageId, abortController);
|
|
49
45
|
// 타임아웃 설정
|
|
50
|
-
|
|
46
|
+
setTimeout(() => {
|
|
51
47
|
console.log(`Message timeout: ${messageId}`);
|
|
52
|
-
abortController.abort();
|
|
53
|
-
this.cleanupMessage(messageId);
|
|
48
|
+
abortController.abort(); // Abort with default reason
|
|
54
49
|
}, RMQ_DEFAULT_MESSAGE_TIMEOUT_MS);
|
|
55
|
-
|
|
50
|
+
console.log('timeout 설정');
|
|
56
51
|
this.runningMessages += 1;
|
|
57
52
|
try {
|
|
58
53
|
// AbortController를 메시지에 추가
|
|
@@ -63,26 +58,23 @@ class GracefulServerRMQ extends microservices_1.ServerRMQ {
|
|
|
63
58
|
// abort 상태 확인
|
|
64
59
|
if (abortController.signal.aborted) {
|
|
65
60
|
console.log(`Message already aborted: ${messageId}`);
|
|
66
|
-
this.cleanupMessage(messageId);
|
|
67
61
|
this.runningMessages -= 1;
|
|
68
62
|
return;
|
|
69
63
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
const abortablePromise = new abortable_promise_1.AbortablePromise((resolve, reject) => {
|
|
65
|
+
try {
|
|
66
|
+
super.handleMessage(message, channel);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
reject(err);
|
|
70
|
+
}
|
|
71
|
+
}, abortController.signal);
|
|
72
|
+
abortablePromise.then((val) => {
|
|
73
|
+
console.log('handleMessage success', val);
|
|
74
|
+
}).catch((err) => {
|
|
75
|
+
console.log('handleMessage error', err);
|
|
76
|
+
throw err;
|
|
80
77
|
});
|
|
81
|
-
// 둘 중 하나가 먼저 완료되면 그 결과를 반환
|
|
82
|
-
await Promise.race([
|
|
83
|
-
handleMessagePromise,
|
|
84
|
-
abortPromise,
|
|
85
|
-
]);
|
|
86
78
|
}
|
|
87
79
|
catch (error) {
|
|
88
80
|
if (error.message.includes('Message aborted')) {
|
|
@@ -94,39 +86,11 @@ class GracefulServerRMQ extends microservices_1.ServerRMQ {
|
|
|
94
86
|
}
|
|
95
87
|
}
|
|
96
88
|
finally {
|
|
97
|
-
this.cleanupMessage(messageId);
|
|
98
89
|
this.runningMessages -= 1;
|
|
99
90
|
}
|
|
100
91
|
}
|
|
101
|
-
cleanupMessage(messageId) {
|
|
102
|
-
// 타임아웃 정리
|
|
103
|
-
const timeoutId = this.messageTimeouts.get(messageId);
|
|
104
|
-
if (timeoutId) {
|
|
105
|
-
clearTimeout(timeoutId);
|
|
106
|
-
this.messageTimeouts.delete(messageId);
|
|
107
|
-
}
|
|
108
|
-
// AbortController 정리
|
|
109
|
-
this.messageAbortControllers.delete(messageId);
|
|
110
|
-
}
|
|
111
|
-
// 특정 메시지 강제 중단
|
|
112
|
-
abortMessage(messageId) {
|
|
113
|
-
const abortController = this.messageAbortControllers.get(messageId);
|
|
114
|
-
if (abortController) {
|
|
115
|
-
abortController.abort();
|
|
116
|
-
this.cleanupMessage(messageId);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
// 모든 실행 중인 메시지 중단
|
|
120
|
-
abortAllMessages() {
|
|
121
|
-
for (const [messageId, abortController,] of this.messageAbortControllers) {
|
|
122
|
-
abortController.abort();
|
|
123
|
-
this.cleanupMessage(messageId);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
92
|
async close() {
|
|
127
93
|
this.closing = true;
|
|
128
|
-
// 모든 실행 중인 메시지 중단
|
|
129
|
-
this.abortAllMessages();
|
|
130
94
|
if (this.channel) {
|
|
131
95
|
await this.channel.removeSetup(undefined, (channel) => channel.cancel(this.consumerTag));
|
|
132
96
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yolo-croket-dev/core",
|
|
3
|
-
"version": "1.7.25-slowquery.
|
|
3
|
+
"version": "1.7.25-slowquery.11",
|
|
4
4
|
"author": "Yolo Co., Ltd.",
|
|
5
5
|
"description": "Yolo commonization module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"license": "UNLICENSED",
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@nestjs/common": "^8.2.3",
|
|
18
|
+
"@xuchaoqian/abortable-promise": "^1.11.2",
|
|
18
19
|
"@yolo-croket-dev/logger": "^1.0.15",
|
|
19
20
|
"@yolo-croket-dev/msa-logger": "^3.0.4",
|
|
20
21
|
"@yolo-croket-dev/redis": "^1.0.23",
|