@yolo-croket-dev/core 1.7.25-slowquery.39 → 1.7.25-slowquery.4
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/functions/index.d.ts +0 -1
- package/functions/index.js +0 -1
- package/interceptors/logging-service.interceptor.js +2 -2
- package/interceptors/rpc.interceptor.d.ts +0 -2
- package/interceptors/rpc.interceptor.js +93 -18
- package/interfaces/exception.js +3 -3
- package/modules/graceful-shutdown/graceful-shutdown.module.js +2 -2
- package/modules/graceful-shutdown/graceful-shutdown.rmq.d.ts +2 -1
- package/modules/graceful-shutdown/graceful-shutdown.rmq.js +90 -2
- package/modules/graceful-shutdown/graceful-shutdown.service.js +2 -2
- package/modules/redis.module.js +2 -2
- package/package.json +2 -2
- package/pipes/rpc-validation.pipe.js +2 -2
- package/functions/abort/abort-context.d.ts +0 -33
- package/functions/abort/abort-context.js +0 -47
- package/functions/abort/abort.d.ts +0 -55
- package/functions/abort/abort.js +0 -231
- package/functions/abort/enhanced-promise-patch.d.ts +0 -17
- package/functions/abort/enhanced-promise-patch.js +0 -115
- package/functions/abort/index.d.ts +0 -3
- package/functions/abort/index.js +0 -19
package/functions/index.d.ts
CHANGED
package/functions/index.js
CHANGED
|
@@ -20,4 +20,3 @@ __exportStar(require("./amqp-publish.function"), exports);
|
|
|
20
20
|
__exportStar(require("./rewrite-file-value.function"), exports);
|
|
21
21
|
__exportStar(require("./amqp-call-manager.function"), exports);
|
|
22
22
|
__exportStar(require("./extract-redis-url.function"), exports);
|
|
23
|
-
__exportStar(require("./abort"), exports);
|
|
@@ -188,7 +188,7 @@ let LoggingServiceInterceptor = class LoggingServiceInterceptor {
|
|
|
188
188
|
}));
|
|
189
189
|
}
|
|
190
190
|
};
|
|
191
|
-
|
|
192
|
-
exports.LoggingServiceInterceptor = LoggingServiceInterceptor = __decorate([
|
|
191
|
+
LoggingServiceInterceptor = __decorate([
|
|
193
192
|
(0, common_1.Injectable)()
|
|
194
193
|
], LoggingServiceInterceptor);
|
|
194
|
+
exports.LoggingServiceInterceptor = LoggingServiceInterceptor;
|
|
@@ -5,8 +5,6 @@ import { GracefulShutdownService } from '../modules/graceful-shutdown/graceful-s
|
|
|
5
5
|
export declare class RPCInterceptor implements NestInterceptor {
|
|
6
6
|
private readonly reflector;
|
|
7
7
|
private readonly gracefulShutdownService;
|
|
8
|
-
protected readonly DEFAULT_TIMEOUT = 1000;
|
|
9
|
-
protected readonly DEFAULT_TIMEOUT_MESSAGE = "\uC694\uCCAD\uC774 \uD0C0\uC784\uC544\uC6C3\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
10
8
|
constructor(reflector: Reflector, gracefulShutdownService: GracefulShutdownService);
|
|
11
9
|
private maxLengthOverShorten;
|
|
12
10
|
/** 메시지가 재전송되었을때에, 재시도 Count가 명시되어 있지 않을때에 처리 할지 여부를 결정하는 함수 */
|
|
@@ -44,9 +44,11 @@ const rxjs_1 = require("rxjs");
|
|
|
44
44
|
const operators_1 = require("rxjs/operators");
|
|
45
45
|
const msa_logger_1 = __importStar(require("@yolo-croket-dev/msa-logger"));
|
|
46
46
|
const amqplib_1 = __importDefault(require("amqplib"));
|
|
47
|
+
// import Logger from '@yolo-croket-dev/logger';
|
|
47
48
|
const functions_1 = require("../functions");
|
|
48
49
|
const exceptions_1 = require("../exceptions");
|
|
49
50
|
const graceful_shutdown_service_1 = require("../modules/graceful-shutdown/graceful-shutdown.service");
|
|
51
|
+
// const logger = Logger.createLogger('RPCInterceptor');
|
|
50
52
|
const msaLogger = new msa_logger_1.default(msa_logger_1.ServerTypeEnum.SERVICE);
|
|
51
53
|
// const MAX_CUT_LENGTH = 500;
|
|
52
54
|
const MAX_LENGTH = 300;
|
|
@@ -54,9 +56,6 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
54
56
|
constructor(reflector, gracefulShutdownService) {
|
|
55
57
|
this.reflector = reflector;
|
|
56
58
|
this.gracefulShutdownService = gracefulShutdownService;
|
|
57
|
-
this.DEFAULT_TIMEOUT = 1000; // 29분 타임아웃
|
|
58
|
-
// protected readonly DEFAULT_TIMEOUT = 1000 * 60 * 29; // 29분 타임아웃
|
|
59
|
-
this.DEFAULT_TIMEOUT_MESSAGE = '요청이 타임아웃되었습니다.';
|
|
60
59
|
}
|
|
61
60
|
maxLengthOverShorten(data) {
|
|
62
61
|
if (typeof data !== 'string') {
|
|
@@ -147,12 +146,48 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
147
146
|
}
|
|
148
147
|
return obj;
|
|
149
148
|
}
|
|
149
|
+
// private keyCutter(data: string) {
|
|
150
|
+
// try {
|
|
151
|
+
// if (data) {
|
|
152
|
+
// data = JSON.parse(data);
|
|
153
|
+
// } else {
|
|
154
|
+
// return data;
|
|
155
|
+
// }
|
|
156
|
+
// } catch (err) {
|
|
157
|
+
// return data;
|
|
158
|
+
// }
|
|
159
|
+
// for (const key of Object.keys(data)) {
|
|
160
|
+
// const type = typeof data[key as any];
|
|
161
|
+
// if (type === 'string') {
|
|
162
|
+
// if (data[key as any].length > MAX_CUT_LENGTH) {
|
|
163
|
+
// (data[key as any] as any) = `${data[key as any].slice(0, MAX_CUT_LENGTH)}...`;
|
|
164
|
+
// }
|
|
165
|
+
// } else if (type === 'object') {
|
|
166
|
+
// if (data[key as any] === null) {
|
|
167
|
+
// (data[key as any] as any) = null;
|
|
168
|
+
// } else {
|
|
169
|
+
// (data[key as any] as any) = this.keyCutter(data[key as any]);
|
|
170
|
+
// }
|
|
171
|
+
// }
|
|
172
|
+
// }
|
|
173
|
+
// return data;
|
|
174
|
+
// }
|
|
150
175
|
async intercept(context, next) {
|
|
151
176
|
var _a, _b, _c, _d, _e;
|
|
152
177
|
const options = this.reflector.get('rpcInterceptorScope', context.getHandler());
|
|
153
178
|
const args = context.getArgs();
|
|
154
179
|
const arg = args[0];
|
|
155
180
|
const rmq = args[1];
|
|
181
|
+
// 메시지에서 AbortController 가져오기
|
|
182
|
+
const abortController = rmq.args[0].abortController;
|
|
183
|
+
// const messageId = (rmq as any).messageId;
|
|
184
|
+
// if (!abortController) {
|
|
185
|
+
// // AbortController가 없으면 기본 처리
|
|
186
|
+
// return next.handle().pipe(
|
|
187
|
+
// timeout(1000 * 60 * 29),
|
|
188
|
+
// // ... 기존 로직
|
|
189
|
+
// );
|
|
190
|
+
// }
|
|
156
191
|
const channel = rmq.getChannelRef();
|
|
157
192
|
const message = rmq.getMessage();
|
|
158
193
|
const now = Date.now();
|
|
@@ -169,7 +204,6 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
169
204
|
correlationId,
|
|
170
205
|
isMessageAck: false,
|
|
171
206
|
};
|
|
172
|
-
const abortController = new AbortController();
|
|
173
207
|
/** consume 메시지 전부 cancel */
|
|
174
208
|
if (this.gracefulShutdownService.isApplicationExit) {
|
|
175
209
|
msaLogger.debug('RPCInterceptor isApplicationExit called', { traceId: 'IS_APPLICATION_EXIT' });
|
|
@@ -230,6 +264,13 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
230
264
|
errMessage,
|
|
231
265
|
errAction,
|
|
232
266
|
};
|
|
267
|
+
// const isTimeoutError = err instanceof Error && err.name === 'TimeoutError';
|
|
268
|
+
// if (isTimeoutError) {
|
|
269
|
+
// channel.nack(message, false, true);
|
|
270
|
+
// message.properties.replyTo = undefined; /** replyTo가 존재하면 sendToQueue가 호출되므로, 삭제해주기 */
|
|
271
|
+
// execInterceptor.isMessageAck = true;
|
|
272
|
+
// return EMPTY;
|
|
273
|
+
// }
|
|
233
274
|
if (!Number.isNaN(staticRetryCount)
|
|
234
275
|
&& staticRetryCount
|
|
235
276
|
&& err.isRetry !== false) {
|
|
@@ -262,6 +303,11 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
262
303
|
const messageContent = message.content.toString();
|
|
263
304
|
/** 파일 객체 처리 */
|
|
264
305
|
(0, functions_1.reWriteFileValue)((_a = messageContent === null || messageContent === void 0 ? void 0 : messageContent.data) === null || _a === void 0 ? void 0 : _a.file);
|
|
306
|
+
// logger.debug(`<= (error:${traceId}): ${JSON.stringify(sendMessage.toString())}`, {
|
|
307
|
+
// ...logParam,
|
|
308
|
+
// duration,
|
|
309
|
+
// isError: true,
|
|
310
|
+
// });
|
|
265
311
|
if (!noAck && !isAck) {
|
|
266
312
|
channel.ack(message);
|
|
267
313
|
execInterceptor.isMessageAck = true;
|
|
@@ -290,20 +336,46 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
290
336
|
return new rxjs_1.Observable();
|
|
291
337
|
}
|
|
292
338
|
}
|
|
339
|
+
if (content.pattern === 'UPLOAD_FILE') {
|
|
340
|
+
if (content.data.payload.file) {
|
|
341
|
+
content.data.payload.file = `${content.data.payload.file.slice(0, 30)}...`;
|
|
342
|
+
}
|
|
343
|
+
// logger.debug(`=> (${traceId}): ${JSON.stringify(this.keyCutter(JSON.stringify(content)))}`);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
// logger.debug(`=> (${traceId}): ${JSON.stringify(this.keyCutter(JSON.stringify(content)))}`);
|
|
347
|
+
}
|
|
293
348
|
this.gracefulShutdownService.pushActiveInterceptors(execInterceptor);
|
|
294
349
|
// eslint-disable-next-line consistent-return
|
|
295
|
-
return
|
|
350
|
+
return next
|
|
296
351
|
.handle()
|
|
297
|
-
.pipe(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
352
|
+
.pipe(
|
|
353
|
+
// AbortController 신호 감지
|
|
354
|
+
(0, operators_1.takeUntil)(new rxjs_1.Observable(subscriber => {
|
|
355
|
+
const abortHandler = () => {
|
|
356
|
+
console.log('RPC Interceptor abortHandler called');
|
|
357
|
+
subscriber.next();
|
|
358
|
+
subscriber.complete();
|
|
359
|
+
};
|
|
360
|
+
console.log('RPC Interceptor abortHandler addEventListener');
|
|
361
|
+
abortController.signal.addEventListener('abort', abortHandler, { once: true });
|
|
362
|
+
// 정리 함수
|
|
363
|
+
return () => {
|
|
364
|
+
abortController.signal.removeEventListener('abort', abortHandler);
|
|
365
|
+
};
|
|
366
|
+
})),
|
|
367
|
+
// timeout(1000 * 60 * 29), // 30분 타임아웃
|
|
368
|
+
(0, operators_1.timeout)(1000 * 30), // 30분 타임아웃
|
|
369
|
+
(0, operators_1.tap)({
|
|
305
370
|
next: async (val) => {
|
|
371
|
+
console.log('RPC Interceptor next called');
|
|
306
372
|
val.isError = false;
|
|
373
|
+
// const duration = Date.now() - now;
|
|
374
|
+
// logger.debug(`<= (success:${traceId}): ${val.message}`, {
|
|
375
|
+
// ...logParam,
|
|
376
|
+
// duration,
|
|
377
|
+
// isError: val.isError,
|
|
378
|
+
// });
|
|
307
379
|
/** 만약 응답데이터중 isRequeue가 true라면, 다시 재처리 하도록 함 */
|
|
308
380
|
if (val.data && val.data.isRequeue) {
|
|
309
381
|
channel.nack(message, false, true);
|
|
@@ -320,8 +392,12 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
320
392
|
// eslint-disable-next-line consistent-return
|
|
321
393
|
(0, operators_1.catchError)(async (err) => {
|
|
322
394
|
// timeout 에러 처리
|
|
323
|
-
const isTimeoutError = err instanceof Error &&
|
|
395
|
+
const isTimeoutError = err instanceof Error && err.name === 'TimeoutError';
|
|
324
396
|
if (isTimeoutError) {
|
|
397
|
+
if (abortController) {
|
|
398
|
+
abortController.abort();
|
|
399
|
+
throw new Error('Message aborted due to timeout');
|
|
400
|
+
}
|
|
325
401
|
msaLogger.error('[타임 아웃] 메시지 재전송 처리', { traceId: execInterceptor.traceId }, {
|
|
326
402
|
error: {
|
|
327
403
|
message: err.message,
|
|
@@ -351,13 +427,12 @@ let RPCInterceptor = class RPCInterceptor {
|
|
|
351
427
|
}
|
|
352
428
|
}), (0, operators_1.finalize)(() => {
|
|
353
429
|
this.gracefulShutdownService.popActiveInterceptors(execInterceptor);
|
|
354
|
-
|
|
355
|
-
})));
|
|
430
|
+
}));
|
|
356
431
|
}
|
|
357
432
|
};
|
|
358
|
-
|
|
359
|
-
exports.RPCInterceptor = RPCInterceptor = __decorate([
|
|
433
|
+
RPCInterceptor = __decorate([
|
|
360
434
|
(0, common_1.Injectable)(),
|
|
361
435
|
__metadata("design:paramtypes", [core_1.Reflector,
|
|
362
436
|
graceful_shutdown_service_1.GracefulShutdownService])
|
|
363
437
|
], RPCInterceptor);
|
|
438
|
+
exports.RPCInterceptor = RPCInterceptor;
|
package/interfaces/exception.js
CHANGED
|
@@ -18,10 +18,9 @@ var ErrActionTypeEnum;
|
|
|
18
18
|
ErrActionTypeEnum["LEGACY_SHOW_TOAST"] = "LEGACY_SHOW_TOAST";
|
|
19
19
|
ErrActionTypeEnum["FORCE_UPDATE"] = "FORCE_UPDATE";
|
|
20
20
|
ErrActionTypeEnum["UPDATE_ACCESS_TOKEN"] = "UPDATE_ACCESS_TOKEN";
|
|
21
|
-
})(ErrActionTypeEnum
|
|
21
|
+
})(ErrActionTypeEnum = exports.ErrActionTypeEnum || (exports.ErrActionTypeEnum = {}));
|
|
22
22
|
class ErrAction {
|
|
23
23
|
}
|
|
24
|
-
exports.ErrAction = ErrAction;
|
|
25
24
|
__decorate([
|
|
26
25
|
(0, swagger_1.ApiProperty)({
|
|
27
26
|
description: '액션 타입',
|
|
@@ -58,9 +57,9 @@ __decorate([
|
|
|
58
57
|
}),
|
|
59
58
|
__metadata("design:type", String)
|
|
60
59
|
], ErrAction.prototype, "webViewUrl", void 0);
|
|
60
|
+
exports.ErrAction = ErrAction;
|
|
61
61
|
class ErrInfo {
|
|
62
62
|
}
|
|
63
|
-
exports.ErrInfo = ErrInfo;
|
|
64
63
|
__decorate([
|
|
65
64
|
(0, swagger_1.ApiProperty)({
|
|
66
65
|
description: '에러 종류 식별자',
|
|
@@ -82,3 +81,4 @@ __decorate([
|
|
|
82
81
|
}),
|
|
83
82
|
__metadata("design:type", ErrAction)
|
|
84
83
|
], ErrInfo.prototype, "action", void 0);
|
|
84
|
+
exports.ErrInfo = ErrInfo;
|
|
@@ -25,8 +25,7 @@ let GracefulShutdownModule = class GracefulShutdownModule {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
|
-
|
|
29
|
-
exports.GracefulShutdownModule = GracefulShutdownModule = __decorate([
|
|
28
|
+
GracefulShutdownModule = __decorate([
|
|
30
29
|
(0, common_1.Global)(),
|
|
31
30
|
(0, common_1.Module)({
|
|
32
31
|
providers: [graceful_shutdown_service_1.GracefulShutdownService],
|
|
@@ -34,3 +33,4 @@ exports.GracefulShutdownModule = GracefulShutdownModule = __decorate([
|
|
|
34
33
|
}),
|
|
35
34
|
__metadata("design:paramtypes", [graceful_shutdown_service_1.GracefulShutdownService])
|
|
36
35
|
], GracefulShutdownModule);
|
|
36
|
+
exports.GracefulShutdownModule = GracefulShutdownModule;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RmqOptions, ServerRMQ } from '@nestjs/microservices';
|
|
2
2
|
import { Channel } from 'amqp-connection-manager';
|
|
3
3
|
import { ConsumeMessage } from 'amqplib';
|
|
4
|
-
export type GracefulRmqOptions = RmqOptions['options'] & {
|
|
4
|
+
export declare type GracefulRmqOptions = RmqOptions['options'] & {
|
|
5
5
|
waitingEndingHandlersTimeoutMs?: number;
|
|
6
6
|
waitingEndingHandlersIntervalMs?: number;
|
|
7
7
|
};
|
|
@@ -17,4 +17,5 @@ export declare class GracefulServerRMQ extends ServerRMQ {
|
|
|
17
17
|
protected waitingHandlers(): Promise<void>;
|
|
18
18
|
handleMessage(message: ConsumeMessage, channel: Channel): Promise<void>;
|
|
19
19
|
close(): Promise<void>;
|
|
20
|
+
private executeWithAbortSignal;
|
|
20
21
|
}
|
|
@@ -6,6 +6,8 @@ const node_util_1 = require("node:util");
|
|
|
6
6
|
const sleep = (0, node_util_1.promisify)(setTimeout);
|
|
7
7
|
const RMQ_DEFAULT_WAITING_ENDING_HANDLERS_TIMEOUT_MS = 5000;
|
|
8
8
|
const RMQ_DEFAULT_WAITING_ENDING_HANDLERS_INTERVAL_MS = 500;
|
|
9
|
+
// const RMQ_DEFAULT_MESSAGE_TIMEOUT_MS = 1000 * 60 * 29; // 29분
|
|
10
|
+
const RMQ_DEFAULT_MESSAGE_TIMEOUT_MS = 1000 * 2; // 2분
|
|
9
11
|
class GracefulServerRMQ extends microservices_1.ServerRMQ {
|
|
10
12
|
constructor(options) {
|
|
11
13
|
super(options);
|
|
@@ -36,10 +38,43 @@ class GracefulServerRMQ extends microservices_1.ServerRMQ {
|
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
async handleMessage(message, channel) {
|
|
41
|
+
const messageId = message.properties.messageId || message.properties.correlationId || `msg_${Date.now()}_${Math.random()}`;
|
|
42
|
+
// AbortController 생성
|
|
43
|
+
const abortController = new AbortController();
|
|
44
|
+
// 타임아웃 설정
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
console.log(`Message timeout: ${messageId}`);
|
|
47
|
+
abortController.abort();
|
|
48
|
+
}, RMQ_DEFAULT_MESSAGE_TIMEOUT_MS);
|
|
49
|
+
console.log('timeout 설정');
|
|
39
50
|
this.runningMessages += 1;
|
|
40
|
-
|
|
51
|
+
try {
|
|
52
|
+
// AbortController를 메시지에 추가
|
|
53
|
+
// eslint-disable-next-line no-param-reassign, @typescript-eslint/no-explicit-any
|
|
54
|
+
message.abortController = abortController;
|
|
55
|
+
// eslint-disable-next-line no-param-reassign
|
|
56
|
+
message.messageId = messageId;
|
|
57
|
+
// abort 상태 확인
|
|
58
|
+
if (abortController.signal.aborted) {
|
|
59
|
+
console.log(`Message already aborted: ${messageId}`);
|
|
60
|
+
this.runningMessages -= 1;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Promise.withResolvers를 사용하여 abort signal 감지
|
|
64
|
+
await this.executeWithAbortSignal(() => super.handleMessage(message, channel), abortController);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error.message.includes('Message aborted')) {
|
|
68
|
+
console.log(`Message processing aborted: ${messageId}`);
|
|
69
|
+
// abort로 인한 에러는 정상적으로 처리된 것으로 간주
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
41
76
|
this.runningMessages -= 1;
|
|
42
|
-
}
|
|
77
|
+
}
|
|
43
78
|
}
|
|
44
79
|
async close() {
|
|
45
80
|
this.closing = true;
|
|
@@ -55,5 +90,58 @@ class GracefulServerRMQ extends microservices_1.ServerRMQ {
|
|
|
55
90
|
this.runningMessages = 0;
|
|
56
91
|
super.close();
|
|
57
92
|
}
|
|
93
|
+
// Promise.withResolvers를 사용한 abort signal 감지
|
|
94
|
+
async executeWithAbortSignal(task, abortController) {
|
|
95
|
+
// Promise.withResolvers 사용
|
|
96
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
97
|
+
let isAborted = false;
|
|
98
|
+
let isResolved = false;
|
|
99
|
+
// eslint-disable-next-line no-undef
|
|
100
|
+
let checkInterval = null;
|
|
101
|
+
// Abort 이벤트 리스너
|
|
102
|
+
const abortHandler = () => {
|
|
103
|
+
if (!isResolved) {
|
|
104
|
+
isAborted = true;
|
|
105
|
+
console.log('Abort signal detected');
|
|
106
|
+
if (checkInterval)
|
|
107
|
+
clearInterval(checkInterval);
|
|
108
|
+
reject(new Error('Message aborted'));
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
// Abort signal 이벤트 리스너 등록
|
|
112
|
+
// eslint-disable-next-line no-undef
|
|
113
|
+
abortController.signal.addEventListener('abort', abortHandler, { once: true });
|
|
114
|
+
// 매우 짧은 간격으로 abort 상태 확인
|
|
115
|
+
checkInterval = setInterval(() => {
|
|
116
|
+
if (abortController.signal.aborted && !isResolved) {
|
|
117
|
+
isAborted = true;
|
|
118
|
+
clearInterval(checkInterval);
|
|
119
|
+
// eslint-disable-next-line no-undef
|
|
120
|
+
abortController.signal.removeEventListener('abort', abortHandler);
|
|
121
|
+
reject(new Error('Message aborted'));
|
|
122
|
+
}
|
|
123
|
+
}, 1); // 1ms마다 확인
|
|
124
|
+
// 원본 task 실행
|
|
125
|
+
task()
|
|
126
|
+
.then((result) => {
|
|
127
|
+
if (!isAborted && !isResolved) {
|
|
128
|
+
isResolved = true;
|
|
129
|
+
if (checkInterval)
|
|
130
|
+
clearInterval(checkInterval);
|
|
131
|
+
abortController.signal.removeEventListener('abort', abortHandler);
|
|
132
|
+
resolve(result);
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
.catch((error) => {
|
|
136
|
+
if (!isAborted && !isResolved) {
|
|
137
|
+
isResolved = true;
|
|
138
|
+
if (checkInterval)
|
|
139
|
+
clearInterval(checkInterval);
|
|
140
|
+
abortController.signal.removeEventListener('abort', abortHandler);
|
|
141
|
+
reject(error);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return promise;
|
|
145
|
+
}
|
|
58
146
|
}
|
|
59
147
|
exports.GracefulServerRMQ = GracefulServerRMQ;
|
|
@@ -137,7 +137,7 @@ let GracefulShutdownService = class GracefulShutdownService {
|
|
|
137
137
|
});
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
|
-
|
|
141
|
-
exports.GracefulShutdownService = GracefulShutdownService = __decorate([
|
|
140
|
+
GracefulShutdownService = __decorate([
|
|
142
141
|
(0, common_1.Injectable)()
|
|
143
142
|
], GracefulShutdownService);
|
|
143
|
+
exports.GracefulShutdownService = GracefulShutdownService;
|
package/modules/redis.module.js
CHANGED
|
@@ -15,10 +15,10 @@ const redisProvider = {
|
|
|
15
15
|
};
|
|
16
16
|
let RedisModule = class RedisModule {
|
|
17
17
|
};
|
|
18
|
-
|
|
19
|
-
exports.RedisModule = RedisModule = __decorate([
|
|
18
|
+
RedisModule = __decorate([
|
|
20
19
|
(0, common_1.Module)({
|
|
21
20
|
providers: [redisProvider],
|
|
22
21
|
exports: [redisProvider],
|
|
23
22
|
})
|
|
24
23
|
], RedisModule);
|
|
24
|
+
exports.RedisModule = RedisModule;
|
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.4",
|
|
4
4
|
"author": "Yolo Co., Ltd.",
|
|
5
5
|
"description": "Yolo commonization module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"uuid": "^8.3.2"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^
|
|
29
|
+
"@types/node": "^16.11.9",
|
|
30
30
|
"@types/randomstring": "^1.1.8",
|
|
31
31
|
"@types/uuid": "^8.3.4"
|
|
32
32
|
}
|
|
@@ -31,8 +31,8 @@ let ValidationPipe = class ValidationPipe {
|
|
|
31
31
|
return value;
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
|
-
|
|
35
|
-
exports.ValidationPipe = ValidationPipe = __decorate([
|
|
34
|
+
ValidationPipe = __decorate([
|
|
36
35
|
(0, common_1.Injectable)(),
|
|
37
36
|
__metadata("design:paramtypes", [Object])
|
|
38
37
|
], ValidationPipe);
|
|
38
|
+
exports.ValidationPipe = ValidationPipe;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
/**
|
|
3
|
-
* AbortSignal을 AsyncLocalStorage를 통해 전역적으로 관리하는 컨텍스트
|
|
4
|
-
*/
|
|
5
|
-
export declare class AbortContext {
|
|
6
|
-
private static asyncLocalStorage;
|
|
7
|
-
/**
|
|
8
|
-
* AbortSignal과 함께 컨텍스트를 실행
|
|
9
|
-
* @param abortSignal 중단 신호
|
|
10
|
-
* @param requestId 요청 ID (디버깅용)
|
|
11
|
-
* @param callback 실행할 콜백 함수
|
|
12
|
-
* @returns 실행 결과
|
|
13
|
-
*/
|
|
14
|
-
static run<T>(abortSignal: AbortSignal, requestId: string, callback: () => T): T;
|
|
15
|
-
/**
|
|
16
|
-
* 현재 컨텍스트의 AbortSignal을 가져옴
|
|
17
|
-
* @returns 현재 AbortSignal 또는 null
|
|
18
|
-
*/
|
|
19
|
-
static getCurrentAbortSignal(): AbortSignal | null;
|
|
20
|
-
/**
|
|
21
|
-
* 현재 컨텍스트의 요청 ID를 가져옴
|
|
22
|
-
* @returns 현재 요청 ID 또는 null
|
|
23
|
-
*/
|
|
24
|
-
static getCurrentRequestId(): string | null;
|
|
25
|
-
/**
|
|
26
|
-
* 현재 컨텍스트 정보를 가져옴
|
|
27
|
-
* @returns 현재 컨텍스트 또는 null
|
|
28
|
-
*/
|
|
29
|
-
static getCurrentContext(): {
|
|
30
|
-
abortSignal: AbortSignal;
|
|
31
|
-
requestId: string;
|
|
32
|
-
} | null;
|
|
33
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AbortContext = void 0;
|
|
4
|
-
const async_hooks_1 = require("async_hooks");
|
|
5
|
-
/**
|
|
6
|
-
* AbortSignal을 AsyncLocalStorage를 통해 전역적으로 관리하는 컨텍스트
|
|
7
|
-
*/
|
|
8
|
-
class AbortContext {
|
|
9
|
-
/**
|
|
10
|
-
* AbortSignal과 함께 컨텍스트를 실행
|
|
11
|
-
* @param abortSignal 중단 신호
|
|
12
|
-
* @param requestId 요청 ID (디버깅용)
|
|
13
|
-
* @param callback 실행할 콜백 함수
|
|
14
|
-
* @returns 실행 결과
|
|
15
|
-
*/
|
|
16
|
-
static run(abortSignal, requestId, callback) {
|
|
17
|
-
return this.asyncLocalStorage.run({
|
|
18
|
-
abortSignal,
|
|
19
|
-
requestId,
|
|
20
|
-
}, callback);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* 현재 컨텍스트의 AbortSignal을 가져옴
|
|
24
|
-
* @returns 현재 AbortSignal 또는 null
|
|
25
|
-
*/
|
|
26
|
-
static getCurrentAbortSignal() {
|
|
27
|
-
const context = this.asyncLocalStorage.getStore();
|
|
28
|
-
return (context === null || context === void 0 ? void 0 : context.abortSignal) || null;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* 현재 컨텍스트의 요청 ID를 가져옴
|
|
32
|
-
* @returns 현재 요청 ID 또는 null
|
|
33
|
-
*/
|
|
34
|
-
static getCurrentRequestId() {
|
|
35
|
-
const context = this.asyncLocalStorage.getStore();
|
|
36
|
-
return (context === null || context === void 0 ? void 0 : context.requestId) || null;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* 현재 컨텍스트 정보를 가져옴
|
|
40
|
-
* @returns 현재 컨텍스트 또는 null
|
|
41
|
-
*/
|
|
42
|
-
static getCurrentContext() {
|
|
43
|
-
return this.asyncLocalStorage.getStore() || null;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
exports.AbortContext = AbortContext;
|
|
47
|
-
AbortContext.asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
/// <reference types="node" />
|
|
3
|
-
/**
|
|
4
|
-
* 현재 컨텍스트의 AbortSignal을 가져오는 전역 함수
|
|
5
|
-
* @returns 현재 AbortSignal 또는 null
|
|
6
|
-
*/
|
|
7
|
-
export declare function getCurrentAbortSignal(): AbortSignal | null;
|
|
8
|
-
/**
|
|
9
|
-
* 현재 AbortSignal이 중단되었는지 확인
|
|
10
|
-
* @returns 중단 여부
|
|
11
|
-
*/
|
|
12
|
-
export declare function isAborted(): boolean;
|
|
13
|
-
/**
|
|
14
|
-
* AbortSignal이 중단되었을 때 에러를 던지는 함수
|
|
15
|
-
* @param message 에러 메시지
|
|
16
|
-
* @throws 중단된 경우 에러 발생
|
|
17
|
-
*/
|
|
18
|
-
export declare function throwIfAborted(message?: string): void;
|
|
19
|
-
/**
|
|
20
|
-
* AbortSignal을 감지하여 중단 가능한 Promise를 생성
|
|
21
|
-
* @param promise 원본 Promise
|
|
22
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
23
|
-
* @returns 중단 가능한 Promise
|
|
24
|
-
*/
|
|
25
|
-
export declare function withAbortSignal<T>(promise: Promise<T>, abortSignal?: AbortSignal): Promise<T>;
|
|
26
|
-
/**
|
|
27
|
-
* AbortSignal을 감지하여 중단 가능한 delay
|
|
28
|
-
* @param ms 지연 시간 (밀리초)
|
|
29
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
30
|
-
* @returns 중단 가능한 Promise
|
|
31
|
-
*/
|
|
32
|
-
export declare function delayWithAbort(ms: number, abortSignal?: AbortSignal): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
* AbortSignal을 감지하여 중단 가능한 setTimeout
|
|
35
|
-
* @param callback 실행할 콜백 함수
|
|
36
|
-
* @param delay 지연 시간 (밀리초)
|
|
37
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
38
|
-
* @returns 타이머 ID
|
|
39
|
-
*/
|
|
40
|
-
export declare function setTimeoutWithAbort(callback: () => void, delay: number, abortSignal?: AbortSignal): NodeJS.Timeout;
|
|
41
|
-
/**
|
|
42
|
-
* AbortSignal을 감지하여 중단 가능한 반복 작업
|
|
43
|
-
* @param task 반복할 작업 함수
|
|
44
|
-
* @param interval 반복 간격 (밀리초)
|
|
45
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
46
|
-
* @returns 중단 가능한 Promise
|
|
47
|
-
*/
|
|
48
|
-
export declare function repeatWithAbort(task: () => Promise<void> | void, interval: number, abortSignal?: AbortSignal): Promise<void>;
|
|
49
|
-
/**
|
|
50
|
-
* 이벤트 기반으로 중단 가능한 Promise 실행
|
|
51
|
-
* @param promise 원본 Promise
|
|
52
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
53
|
-
* @returns 중단 가능한 Promise
|
|
54
|
-
*/
|
|
55
|
-
export declare function withAbortSignalEventBased<T>(promise: Promise<T>, abortSignal?: AbortSignal): Promise<T>;
|
package/functions/abort/abort.js
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.withAbortSignalEventBased = exports.repeatWithAbort = exports.setTimeoutWithAbort = exports.delayWithAbort = exports.withAbortSignal = exports.throwIfAborted = exports.isAborted = exports.getCurrentAbortSignal = void 0;
|
|
4
|
-
const abort_context_1 = require("./abort-context");
|
|
5
|
-
/**
|
|
6
|
-
* 현재 컨텍스트의 AbortSignal을 가져오는 전역 함수
|
|
7
|
-
* @returns 현재 AbortSignal 또는 null
|
|
8
|
-
*/
|
|
9
|
-
function getCurrentAbortSignal() {
|
|
10
|
-
return abort_context_1.AbortContext.getCurrentAbortSignal();
|
|
11
|
-
}
|
|
12
|
-
exports.getCurrentAbortSignal = getCurrentAbortSignal;
|
|
13
|
-
/**
|
|
14
|
-
* 현재 AbortSignal이 중단되었는지 확인
|
|
15
|
-
* @returns 중단 여부
|
|
16
|
-
*/
|
|
17
|
-
function isAborted() {
|
|
18
|
-
var _a;
|
|
19
|
-
const signal = getCurrentAbortSignal();
|
|
20
|
-
return (_a = signal === null || signal === void 0 ? void 0 : signal.aborted) !== null && _a !== void 0 ? _a : false;
|
|
21
|
-
}
|
|
22
|
-
exports.isAborted = isAborted;
|
|
23
|
-
/**
|
|
24
|
-
* AbortSignal이 중단되었을 때 에러를 던지는 함수
|
|
25
|
-
* @param message 에러 메시지
|
|
26
|
-
* @throws 중단된 경우 에러 발생
|
|
27
|
-
*/
|
|
28
|
-
function throwIfAborted(message = '작업이 중단되었습니다') {
|
|
29
|
-
if (isAborted()) {
|
|
30
|
-
throw new Error(`REQUEST_ABORTED: ${message}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
exports.throwIfAborted = throwIfAborted;
|
|
34
|
-
/**
|
|
35
|
-
* AbortSignal을 감지하여 중단 가능한 Promise를 생성
|
|
36
|
-
* @param promise 원본 Promise
|
|
37
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
38
|
-
* @returns 중단 가능한 Promise
|
|
39
|
-
*/
|
|
40
|
-
function withAbortSignal(promise, abortSignal) {
|
|
41
|
-
const signal = abortSignal || getCurrentAbortSignal();
|
|
42
|
-
if (!signal) {
|
|
43
|
-
return promise;
|
|
44
|
-
}
|
|
45
|
-
return new Promise((resolve, reject) => {
|
|
46
|
-
// 이미 중단된 경우
|
|
47
|
-
if (signal.aborted) {
|
|
48
|
-
reject(new Error('REQUEST_ABORTED: 작업이 이미 중단되었습니다'));
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
// 중단 이벤트 리스너 등록
|
|
52
|
-
const abortHandler = () => {
|
|
53
|
-
reject(new Error('REQUEST_ABORTED: 작업이 중단되었습니다'));
|
|
54
|
-
};
|
|
55
|
-
signal.addEventListener('abort', abortHandler, { once: true });
|
|
56
|
-
// 원본 Promise 처리
|
|
57
|
-
promise
|
|
58
|
-
.then((result) => {
|
|
59
|
-
signal.removeEventListener('abort', abortHandler);
|
|
60
|
-
resolve(result);
|
|
61
|
-
})
|
|
62
|
-
.catch((error) => {
|
|
63
|
-
signal.removeEventListener('abort', abortHandler);
|
|
64
|
-
reject(error);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
exports.withAbortSignal = withAbortSignal;
|
|
69
|
-
/**
|
|
70
|
-
* AbortSignal을 감지하여 중단 가능한 delay
|
|
71
|
-
* @param ms 지연 시간 (밀리초)
|
|
72
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
73
|
-
* @returns 중단 가능한 Promise
|
|
74
|
-
*/
|
|
75
|
-
function delayWithAbort(ms, abortSignal) {
|
|
76
|
-
const signal = abortSignal || getCurrentAbortSignal();
|
|
77
|
-
return new Promise((resolve, reject) => {
|
|
78
|
-
if (!signal) {
|
|
79
|
-
setTimeout(resolve, ms);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
// 이미 중단된 경우
|
|
83
|
-
if (signal.aborted) {
|
|
84
|
-
reject(new Error('REQUEST_ABORTED: 작업이 이미 중단되었습니다'));
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const timerId = setTimeout(() => {
|
|
88
|
-
if (!signal.aborted) {
|
|
89
|
-
resolve();
|
|
90
|
-
}
|
|
91
|
-
}, ms);
|
|
92
|
-
// 중단 이벤트 리스너 등록
|
|
93
|
-
const abortHandler = () => {
|
|
94
|
-
clearTimeout(timerId);
|
|
95
|
-
reject(new Error('REQUEST_ABORTED: 작업이 중단되었습니다'));
|
|
96
|
-
};
|
|
97
|
-
signal.addEventListener('abort', abortHandler, { once: true });
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
exports.delayWithAbort = delayWithAbort;
|
|
101
|
-
/**
|
|
102
|
-
* AbortSignal을 감지하여 중단 가능한 setTimeout
|
|
103
|
-
* @param callback 실행할 콜백 함수
|
|
104
|
-
* @param delay 지연 시간 (밀리초)
|
|
105
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
106
|
-
* @returns 타이머 ID
|
|
107
|
-
*/
|
|
108
|
-
function setTimeoutWithAbort(callback, delay, abortSignal) {
|
|
109
|
-
const signal = abortSignal || getCurrentAbortSignal();
|
|
110
|
-
if (!signal) {
|
|
111
|
-
return setTimeout(callback, delay);
|
|
112
|
-
}
|
|
113
|
-
// 이미 중단된 경우
|
|
114
|
-
if (signal.aborted) {
|
|
115
|
-
throw new Error('REQUEST_ABORTED: 작업이 이미 중단되었습니다');
|
|
116
|
-
}
|
|
117
|
-
const timerId = setTimeout(() => {
|
|
118
|
-
if (!signal.aborted) {
|
|
119
|
-
callback();
|
|
120
|
-
}
|
|
121
|
-
}, delay);
|
|
122
|
-
// 중단 이벤트 리스너 등록
|
|
123
|
-
const abortHandler = () => {
|
|
124
|
-
clearTimeout(timerId);
|
|
125
|
-
};
|
|
126
|
-
signal.addEventListener('abort', abortHandler, { once: true });
|
|
127
|
-
return timerId;
|
|
128
|
-
}
|
|
129
|
-
exports.setTimeoutWithAbort = setTimeoutWithAbort;
|
|
130
|
-
/**
|
|
131
|
-
* AbortSignal을 감지하여 중단 가능한 반복 작업
|
|
132
|
-
* @param task 반복할 작업 함수
|
|
133
|
-
* @param interval 반복 간격 (밀리초)
|
|
134
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
135
|
-
* @returns 중단 가능한 Promise
|
|
136
|
-
*/
|
|
137
|
-
function repeatWithAbort(task, interval, abortSignal) {
|
|
138
|
-
const signal = abortSignal || getCurrentAbortSignal();
|
|
139
|
-
return new Promise((resolve, reject) => {
|
|
140
|
-
if (!signal) {
|
|
141
|
-
// abortSignal이 없으면 일반적인 반복 실행
|
|
142
|
-
const runTask = async () => {
|
|
143
|
-
try {
|
|
144
|
-
await task();
|
|
145
|
-
setTimeout(runTask, interval);
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
reject(error);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
runTask();
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
// 이미 중단된 경우
|
|
155
|
-
if (signal.aborted) {
|
|
156
|
-
reject(new Error('REQUEST_ABORTED: 작업이 이미 중단되었습니다'));
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
const runTask = async () => {
|
|
160
|
-
if (signal.aborted) {
|
|
161
|
-
reject(new Error('REQUEST_ABORTED: 작업이 중단되었습니다'));
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
try {
|
|
165
|
-
await task();
|
|
166
|
-
if (!signal.aborted) {
|
|
167
|
-
setTimeout(runTask, interval);
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
reject(new Error('REQUEST_ABORTED: 작업이 중단되었습니다'));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
catch (error) {
|
|
174
|
-
reject(error);
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
// 중단 이벤트 리스너 등록
|
|
178
|
-
const abortHandler = () => {
|
|
179
|
-
reject(new Error('REQUEST_ABORTED: 작업이 중단되었습니다'));
|
|
180
|
-
};
|
|
181
|
-
signal.addEventListener('abort', abortHandler, { once: true });
|
|
182
|
-
runTask();
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
exports.repeatWithAbort = repeatWithAbort;
|
|
186
|
-
/**
|
|
187
|
-
* 이벤트 기반으로 중단 가능한 Promise 실행
|
|
188
|
-
* @param promise 원본 Promise
|
|
189
|
-
* @param abortSignal 중단 신호 (선택사항, 없으면 현재 컨텍스트에서 가져옴)
|
|
190
|
-
* @returns 중단 가능한 Promise
|
|
191
|
-
*/
|
|
192
|
-
function withAbortSignalEventBased(promise, abortSignal) {
|
|
193
|
-
const signal = abortSignal || getCurrentAbortSignal();
|
|
194
|
-
if (!signal) {
|
|
195
|
-
return promise;
|
|
196
|
-
}
|
|
197
|
-
return new Promise((resolve, reject) => {
|
|
198
|
-
// 이미 중단된 경우
|
|
199
|
-
if (signal.aborted) {
|
|
200
|
-
reject(new Error('REQUEST_ABORTED: 작업이 이미 중단되었습니다'));
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
let isCompleted = false;
|
|
204
|
-
// abort 이벤트 리스너 (즉시 반응)
|
|
205
|
-
const abortHandler = () => {
|
|
206
|
-
if (!isCompleted) {
|
|
207
|
-
isCompleted = true;
|
|
208
|
-
reject(new Error('REQUEST_ABORTED: 작업이 중단되었습니다'));
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
// 이벤트 리스너 등록
|
|
212
|
-
signal.addEventListener('abort', abortHandler, { once: true });
|
|
213
|
-
// 원본 Promise 처리
|
|
214
|
-
promise
|
|
215
|
-
.then((result) => {
|
|
216
|
-
if (!isCompleted) {
|
|
217
|
-
isCompleted = true;
|
|
218
|
-
signal.removeEventListener('abort', abortHandler);
|
|
219
|
-
resolve(result);
|
|
220
|
-
}
|
|
221
|
-
})
|
|
222
|
-
.catch((error) => {
|
|
223
|
-
if (!isCompleted) {
|
|
224
|
-
isCompleted = true;
|
|
225
|
-
signal.removeEventListener('abort', abortHandler);
|
|
226
|
-
reject(error);
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
exports.withAbortSignalEventBased = withAbortSignalEventBased;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
declare global {
|
|
2
|
-
var Promise: PromiseConstructor;
|
|
3
|
-
}
|
|
4
|
-
export declare class EnhancedPromisePatch {
|
|
5
|
-
private static isPatched;
|
|
6
|
-
private static originalPromise;
|
|
7
|
-
private static originalSetTimeout;
|
|
8
|
-
static patch(): void;
|
|
9
|
-
private static patchPromise;
|
|
10
|
-
private static patchSetTimeout;
|
|
11
|
-
static unpatch(): void;
|
|
12
|
-
/**
|
|
13
|
-
* 현재 패치 상태 확인
|
|
14
|
-
* @returns 패치 여부
|
|
15
|
-
*/
|
|
16
|
-
static getPatchStatus(): boolean;
|
|
17
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EnhancedPromisePatch = void 0;
|
|
4
|
-
const abort_1 = require("./abort");
|
|
5
|
-
class EnhancedPromisePatch {
|
|
6
|
-
static patch() {
|
|
7
|
-
if (this.isPatched) {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
this.patchPromise();
|
|
11
|
-
this.patchSetTimeout();
|
|
12
|
-
this.isPatched = true;
|
|
13
|
-
}
|
|
14
|
-
static patchPromise() {
|
|
15
|
-
this.originalPromise = global.Promise;
|
|
16
|
-
// Promise 생성자 패치
|
|
17
|
-
global.Promise = new Proxy(global.Promise, {
|
|
18
|
-
construct(target, args) {
|
|
19
|
-
const abortSignal = (0, abort_1.getCurrentAbortSignal)();
|
|
20
|
-
if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
|
|
21
|
-
return Promise.reject(new Error('REQUEST_ABORTED: Promise가 중단되었습니다'));
|
|
22
|
-
}
|
|
23
|
-
// target은 Promise 생성자이므로, new 연산자와 함께 사용해야 하며, args는 [executor] 형태의 튜플임을 명시합니다.
|
|
24
|
-
const promise = Reflect.construct(target, args);
|
|
25
|
-
if (!abortSignal) {
|
|
26
|
-
return promise;
|
|
27
|
-
}
|
|
28
|
-
// Promise 체인에 중단 확인 추가
|
|
29
|
-
return promise.then((result) => {
|
|
30
|
-
if (abortSignal.aborted) {
|
|
31
|
-
throw new Error('REQUEST_ABORTED: Promise 실행 중 중단되었습니다');
|
|
32
|
-
}
|
|
33
|
-
return result;
|
|
34
|
-
}, (error) => {
|
|
35
|
-
if (abortSignal.aborted) {
|
|
36
|
-
throw new Error('REQUEST_ABORTED: Promise 실행 중 중단되었습니다');
|
|
37
|
-
}
|
|
38
|
-
throw error;
|
|
39
|
-
});
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
// Promise.resolve 패치
|
|
43
|
-
const originalResolve = global.Promise.resolve;
|
|
44
|
-
global.Promise.resolve = (value) => {
|
|
45
|
-
const abortSignal = (0, abort_1.getCurrentAbortSignal)();
|
|
46
|
-
if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
|
|
47
|
-
return Promise.reject(new Error('REQUEST_ABORTED: Promise.resolve가 중단되었습니다'));
|
|
48
|
-
}
|
|
49
|
-
const promise = originalResolve.call(global.Promise, value);
|
|
50
|
-
if (!abortSignal) {
|
|
51
|
-
return promise;
|
|
52
|
-
}
|
|
53
|
-
return promise.then((result) => {
|
|
54
|
-
if (abortSignal.aborted) {
|
|
55
|
-
throw new Error('REQUEST_ABORTED: Promise.resolve 실행 중 중단되었습니다');
|
|
56
|
-
}
|
|
57
|
-
return result;
|
|
58
|
-
}, (error) => {
|
|
59
|
-
if (abortSignal.aborted) {
|
|
60
|
-
throw new Error('REQUEST_ABORTED: Promise.resolve 실행 중 중단되었습니다');
|
|
61
|
-
}
|
|
62
|
-
throw error;
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
// Promise.reject 패치
|
|
66
|
-
const originalReject = global.Promise.reject;
|
|
67
|
-
global.Promise.reject = (reason) => {
|
|
68
|
-
const abortSignal = (0, abort_1.getCurrentAbortSignal)();
|
|
69
|
-
if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
|
|
70
|
-
return Promise.reject(new Error('REQUEST_ABORTED: Promise.reject가 중단되었습니다'));
|
|
71
|
-
}
|
|
72
|
-
return originalReject.call(global.Promise, reason);
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
static patchSetTimeout() {
|
|
76
|
-
this.originalSetTimeout = global.setTimeout;
|
|
77
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
78
|
-
global.setTimeout = (callback, delay, ...args) => {
|
|
79
|
-
const abortSignal = (0, abort_1.getCurrentAbortSignal)();
|
|
80
|
-
if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
|
|
81
|
-
throw new Error('REQUEST_ABORTED: setTimeout이 중단되었습니다');
|
|
82
|
-
}
|
|
83
|
-
const timerId = this.originalSetTimeout(() => {
|
|
84
|
-
if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
|
|
85
|
-
throw new Error('REQUEST_ABORTED: setTimeout 콜백이 중단되었습니다');
|
|
86
|
-
}
|
|
87
|
-
callback(...args);
|
|
88
|
-
}, delay);
|
|
89
|
-
if (abortSignal) {
|
|
90
|
-
const abortHandler = () => {
|
|
91
|
-
clearTimeout(timerId);
|
|
92
|
-
};
|
|
93
|
-
abortSignal.addEventListener('abort', abortHandler, { once: true });
|
|
94
|
-
}
|
|
95
|
-
return timerId;
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
static unpatch() {
|
|
99
|
-
if (!this.isPatched) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
global.Promise = this.originalPromise;
|
|
103
|
-
global.setTimeout = this.originalSetTimeout;
|
|
104
|
-
this.isPatched = false;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* 현재 패치 상태 확인
|
|
108
|
-
* @returns 패치 여부
|
|
109
|
-
*/
|
|
110
|
-
static getPatchStatus() {
|
|
111
|
-
return this.isPatched;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
exports.EnhancedPromisePatch = EnhancedPromisePatch;
|
|
115
|
-
EnhancedPromisePatch.isPatched = false;
|
package/functions/abort/index.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./abort"), exports);
|
|
18
|
-
__exportStar(require("./abort-context"), exports);
|
|
19
|
-
__exportStar(require("./enhanced-promise-patch"), exports);
|