@yolo-croket-dev/core 1.7.44-slowquery.3 → 1.7.44-slowquery.5

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.
@@ -5,19 +5,12 @@ export declare class ContextPromisePatch {
5
5
  private static originalSetInterval;
6
6
  private static originalClearTimeout;
7
7
  private static originalClearInterval;
8
- private static activeAbortListeners;
8
+ private static contextTimers;
9
+ private static timerContextMap;
9
10
  /**
10
- * abort 리스너를 추적
11
+ * 특정 컨텍스트의 모든 타이머 정리
11
12
  */
12
- static registerAbortListener(contextId: string): void;
13
- /**
14
- * abort 리스너 완료
15
- */
16
- static unregisterAbortListener(contextId: string): void;
17
- /**
18
- * 특정 컨텍스트의 모든 abort 리스너가 완료될 때까지 대기
19
- */
20
- static waitForAbortListeners(contextId: string, timeout?: number): Promise<void>;
13
+ static clearContextTimers(contextId: string): void;
21
14
  static patch(): void;
22
15
  private static patchPromise;
23
16
  private static patchTimeouts;
@@ -4,33 +4,17 @@ exports.ContextPromisePatch = void 0;
4
4
  const abort_context_1 = require("./abort-context");
5
5
  class ContextPromisePatch {
6
6
  /**
7
- * abort 리스너를 추적
7
+ * 특정 컨텍스트의 모든 타이머 정리
8
8
  */
9
- static registerAbortListener(contextId) {
10
- this.activeAbortListeners.add(contextId);
11
- }
12
- /**
13
- * abort 리스너 완료
14
- */
15
- static unregisterAbortListener(contextId) {
16
- this.activeAbortListeners.delete(contextId);
17
- }
18
- /**
19
- * 특정 컨텍스트의 모든 abort 리스너가 완료될 때까지 대기
20
- */
21
- static async waitForAbortListeners(contextId, timeout = 1000) {
22
- const startTime = Date.now();
23
- while (this.activeAbortListeners.has(contextId)) {
24
- if (Date.now() - startTime > timeout) {
25
- // 타임아웃
26
- break;
9
+ static clearContextTimers(contextId) {
10
+ const timers = this.contextTimers.get(contextId);
11
+ if (timers) {
12
+ for (const timerId of timers) {
13
+ this.originalClearTimeout(timerId);
14
+ this.originalClearInterval(timerId);
15
+ this.timerContextMap.delete(timerId);
27
16
  }
28
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
- await new Promise((resolve) => {
30
- setTimeout(() => {
31
- resolve();
32
- }, 10);
33
- });
17
+ this.contextTimers.delete(contextId);
34
18
  }
35
19
  }
36
20
  static patch() {
@@ -182,14 +166,21 @@ class ContextPromisePatch {
182
166
  contextId,
183
167
  abortSignal,
184
168
  });
169
+ // 타이머 추적
170
+ if (!this.contextTimers.has(contextId)) {
171
+ this.contextTimers.set(contextId, new Set());
172
+ }
173
+ this.contextTimers.get(contextId).add(timeoutId);
174
+ this.timerContextMap.set(timeoutId, contextId);
175
+ // 클로저로 필요한 정보를 캡처 (컨텍스트가 disable되어도 동작)
176
+ const capturedContextId = contextId;
177
+ const capturedActiveTimers = activeTimers;
185
178
  const onAbort = () => {
186
- ContextPromisePatch.registerAbortListener(contextId);
187
- // 비동기로 처리해서 이벤트 루프에서 실행되도록 함
188
- setTimeout(() => {
189
- this.originalClearTimeout(timeoutId);
190
- activeTimers.delete(timeoutId);
191
- ContextPromisePatch.unregisterAbortListener(contextId);
192
- }, 0);
179
+ var _a;
180
+ this.originalClearTimeout(timeoutId);
181
+ capturedActiveTimers.delete(timeoutId);
182
+ (_a = this.contextTimers.get(capturedContextId)) === null || _a === void 0 ? void 0 : _a.delete(timeoutId);
183
+ this.timerContextMap.delete(timeoutId);
193
184
  };
194
185
  abortSignal.addEventListener('abort', onAbort, { once: true });
195
186
  return timeoutId;
@@ -234,14 +225,21 @@ class ContextPromisePatch {
234
225
  contextId,
235
226
  abortSignal,
236
227
  });
228
+ // 타이머 추적
229
+ if (!this.contextTimers.has(contextId)) {
230
+ this.contextTimers.set(contextId, new Set());
231
+ }
232
+ this.contextTimers.get(contextId).add(intervalId);
233
+ this.timerContextMap.set(intervalId, contextId);
234
+ // 클로저로 필요한 정보를 캡처 (컨텍스트가 disable되어도 동작)
235
+ const capturedContextId = contextId;
236
+ const capturedActiveTimers = activeTimers;
237
237
  const onAbort = () => {
238
- ContextPromisePatch.registerAbortListener(contextId);
239
- // 비동기로 처리해서 이벤트 루프에서 실행되도록 함
240
- setTimeout(() => {
241
- this.originalClearInterval(intervalId);
242
- activeTimers.delete(intervalId);
243
- ContextPromisePatch.unregisterAbortListener(contextId);
244
- }, 0);
238
+ var _a;
239
+ this.originalClearInterval(intervalId);
240
+ capturedActiveTimers.delete(intervalId);
241
+ (_a = this.contextTimers.get(capturedContextId)) === null || _a === void 0 ? void 0 : _a.delete(intervalId);
242
+ this.timerContextMap.delete(intervalId);
245
243
  };
246
244
  abortSignal.addEventListener('abort', onAbort, { once: true });
247
245
  return intervalId;
@@ -249,13 +247,25 @@ class ContextPromisePatch {
249
247
  // clearTimeout 패치
250
248
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
251
249
  global.clearTimeout = (timerId) => {
250
+ var _a;
252
251
  activeTimers.delete(timerId);
252
+ const contextId = this.timerContextMap.get(timerId);
253
+ if (contextId) {
254
+ (_a = this.contextTimers.get(contextId)) === null || _a === void 0 ? void 0 : _a.delete(timerId);
255
+ this.timerContextMap.delete(timerId);
256
+ }
253
257
  this.originalClearTimeout(timerId);
254
258
  };
255
259
  // clearInterval 패치
256
260
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
257
261
  global.clearInterval = (timerId) => {
262
+ var _a;
258
263
  activeTimers.delete(timerId);
264
+ const contextId = this.timerContextMap.get(timerId);
265
+ if (contextId) {
266
+ (_a = this.contextTimers.get(contextId)) === null || _a === void 0 ? void 0 : _a.delete(timerId);
267
+ this.timerContextMap.delete(timerId);
268
+ }
259
269
  this.originalClearInterval(timerId);
260
270
  };
261
271
  }
@@ -273,5 +283,9 @@ class ContextPromisePatch {
273
283
  }
274
284
  exports.ContextPromisePatch = ContextPromisePatch;
275
285
  ContextPromisePatch.isPatched = false;
276
- // abort 리스너 추적
277
- ContextPromisePatch.activeAbortListeners = new Set();
286
+ // 컨텍스트별 활성 타이머 추적 (contextId -> Set<timerId>)
287
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
288
+ ContextPromisePatch.contextTimers = new Map();
289
+ // timerId -> contextId 매핑
290
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
291
+ ContextPromisePatch.timerContextMap = new Map();
@@ -355,12 +355,15 @@ let RPCInterceptor = class RPCInterceptor {
355
355
  }
356
356
  },
357
357
  error: localErrorProcessor,
358
- }), (0, operators_1.finalize)(async () => {
358
+ }), (0, operators_1.finalize)(() => {
359
359
  this.gracefulShutdownService.popActiveInterceptors(execInterceptor);
360
- // abort 이벤트 리스너가 모두 완료될 때까지 기다림
361
- await context_promise_patch_1.ContextPromisePatch.waitForAbortListeners(execInterceptor.traceId);
362
- functions_1.AbortContext.disable();
360
+ // 활성 타이머를 모두 정리
361
+ context_promise_patch_1.ContextPromisePatch.clearContextTimers(execInterceptor.traceId);
363
362
  abortController = null;
363
+ // disable을 충분히 지연시켜서 모든 이벤트 리스너가 완료될 때까지 기다림
364
+ setTimeout(() => {
365
+ functions_1.AbortContext.disable();
366
+ }, 100);
364
367
  return rxjs_1.EMPTY;
365
368
  })));
366
369
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolo-croket-dev/core",
3
- "version": "1.7.44-slowquery.3",
3
+ "version": "1.7.44-slowquery.5",
4
4
  "author": "Yolo Co., Ltd.",
5
5
  "description": "Yolo commonization module",
6
6
  "main": "index.js",