@yolo-croket-dev/core 1.7.31 → 1.7.32-slowquery.1

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.
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  export declare class AbortContext {
3
3
  private static asyncLocalStorage;
4
+ private static contextCounter;
4
5
  static run<T>(abortSignal: AbortSignal, requestId: string, callback: () => T): T;
5
6
  static getCurrentAbortSignal(): AbortSignal | null;
6
7
  static getCurrentRequestId(): string | null;
@@ -7,7 +7,8 @@ class AbortContext {
7
7
  const currentContext = this.asyncLocalStorage.getStore();
8
8
  const newContext = {
9
9
  abortSignal,
10
- requestId,
10
+ // eslint-disable-next-line no-plusplus
11
+ requestId: `ctx_${++this.contextCounter}_${Date.now()}`,
11
12
  createdAt: Date.now(),
12
13
  parentContext: currentContext || undefined,
13
14
  };
@@ -57,3 +58,4 @@ class AbortContext {
57
58
  }
58
59
  exports.AbortContext = AbortContext;
59
60
  AbortContext.asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
61
+ AbortContext.contextCounter = 0;
@@ -1,6 +1,9 @@
1
1
  export declare class ContextPromisePatch {
2
- private static originalPromise;
3
2
  private static isPatched;
3
+ private static originalPromise;
4
+ private static originalSetTimeout;
4
5
  static patch(): void;
6
+ private static patchPromise;
7
+ private static patchSetTimeout;
5
8
  static unpatch(): void;
6
9
  }
@@ -8,41 +8,145 @@ class ContextPromisePatch {
8
8
  return;
9
9
  }
10
10
  this.originalPromise = global.Promise;
11
- // Promise 생성자 패치 - 컨텍스트가 있을 때만 동작
11
+ this.patchPromise();
12
+ this.patchSetTimeout();
13
+ this.isPatched = true;
14
+ }
15
+ static patchPromise() {
16
+ // Promise 생성자 패치
12
17
  global.Promise = new Proxy(global.Promise, {
13
18
  construct(target, args) {
19
+ // 현재 컨텍스트 확인
14
20
  const currentContext = abort_context_1.AbortContext.getCurrentContext();
15
21
  // 컨텍스트가 없으면 원본 Promise 사용
16
22
  if (!currentContext) {
17
23
  return Reflect.construct(target, args);
18
24
  }
19
25
  const abortSignal = currentContext.abortSignal;
20
- if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
21
- return Promise.reject(new Error('REQUEST_ABORTED: Promise가 중단되었습니다'));
26
+ const contextId = currentContext.requestId;
27
+ // 이미 중단된 경우
28
+ if (abortSignal.aborted) {
29
+ return Promise.reject(new Error(`REQUEST_ABORTED: Promise가 중단되었습니다 (${contextId})`));
22
30
  }
23
- // eslint-disable-next-line new-cap
24
31
  const promise = Reflect.construct(target, args);
25
- // 컨텍스트가 있는 경우에만 중단 확인 추가
32
+ // Promise 체인에 자동으로 중단 확인 추가
26
33
  return promise.then((result) => {
34
+ // 컨텍스트가 여전히 유효한지 확인
35
+ const currentContextCheck = abort_context_1.AbortContext.getCurrentContext();
36
+ if (!currentContextCheck || currentContextCheck.requestId !== contextId) {
37
+ // 컨텍스트가 변경되었으면 원본 결과 반환
38
+ return result;
39
+ }
27
40
  if (abortSignal.aborted) {
28
- throw new Error('REQUEST_ABORTED: Promise 실행 중 중단되었습니다');
41
+ throw new Error(`REQUEST_ABORTED: Promise 실행 중 중단되었습니다 (${contextId})`);
29
42
  }
30
43
  return result;
31
44
  }, (error) => {
45
+ // 컨텍스트가 여전히 유효한지 확인
46
+ const currentContextCheck = abort_context_1.AbortContext.getCurrentContext();
47
+ if (!currentContextCheck || currentContextCheck.requestId !== contextId) {
48
+ // 컨텍스트가 변경되었으면 원본 에러 반환
49
+ throw error;
50
+ }
32
51
  if (abortSignal.aborted) {
33
- throw new Error('REQUEST_ABORTED: Promise 실행 중 중단되었습니다');
52
+ throw new Error(`REQUEST_ABORTED: Promise 실행 중 중단되었습니다 (${contextId})`);
34
53
  }
35
54
  throw error;
36
55
  });
37
56
  },
38
57
  });
39
- this.isPatched = true;
58
+ // Promise.resolve 패치
59
+ const originalResolve = global.Promise.resolve;
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ global.Promise.resolve = (value) => {
62
+ const currentContext = abort_context_1.AbortContext.getCurrentContext();
63
+ if (!currentContext) {
64
+ return originalResolve.call(global.Promise, value);
65
+ }
66
+ const abortSignal = currentContext.abortSignal;
67
+ const contextId = currentContext.requestId;
68
+ if (abortSignal.aborted) {
69
+ return Promise.reject(new Error(`REQUEST_ABORTED: Promise.resolve가 중단되었습니다 (${contextId})`));
70
+ }
71
+ const promise = originalResolve.call(global.Promise, value);
72
+ return promise.then((result) => {
73
+ const currentContextCheck = abort_context_1.AbortContext.getCurrentContext();
74
+ if (!currentContextCheck || currentContextCheck.requestId !== contextId) {
75
+ return result;
76
+ }
77
+ if (abortSignal.aborted) {
78
+ throw new Error(`REQUEST_ABORTED: Promise.resolve 실행 중 중단되었습니다 (${contextId})`);
79
+ }
80
+ return result;
81
+ }, (error) => {
82
+ const currentContextCheck = abort_context_1.AbortContext.getCurrentContext();
83
+ if (!currentContextCheck || currentContextCheck.requestId !== contextId) {
84
+ throw error;
85
+ }
86
+ if (abortSignal.aborted) {
87
+ throw new Error(`REQUEST_ABORTED: Promise.resolve 실행 중 중단되었습니다 (${contextId})`);
88
+ }
89
+ throw error;
90
+ });
91
+ };
92
+ // Promise.reject 패치
93
+ const originalReject = global.Promise.reject;
94
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
+ global.Promise.reject = (reason) => {
96
+ const currentContext = abort_context_1.AbortContext.getCurrentContext();
97
+ if (!currentContext) {
98
+ return originalReject.call(global.Promise, reason);
99
+ }
100
+ const abortSignal = currentContext.abortSignal;
101
+ if (abortSignal.aborted) {
102
+ return Promise.reject(new Error(`REQUEST_ABORTED: Promise.reject가 중단되었습니다 (${currentContext.requestId})`));
103
+ }
104
+ return originalReject.call(global.Promise, reason);
105
+ };
106
+ }
107
+ static patchSetTimeout() {
108
+ this.originalSetTimeout = global.setTimeout;
109
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
110
+ global.setTimeout = (callback, delay, ...args) => {
111
+ const currentContext = abort_context_1.AbortContext.getCurrentContext();
112
+ if (!currentContext) {
113
+ return this.originalSetTimeout(callback, delay, ...args);
114
+ }
115
+ const abortSignal = currentContext.abortSignal;
116
+ const contextId = currentContext.requestId;
117
+ if (abortSignal.aborted) {
118
+ throw new Error(`REQUEST_ABORTED: setTimeout이 중단되었습니다 (${contextId})`);
119
+ }
120
+ const wrappedCallback = () => {
121
+ // 컨텍스트가 여전히 유효한지 확인
122
+ const currentContextCheck = abort_context_1.AbortContext.getCurrentContext();
123
+ if (!currentContextCheck || currentContextCheck.requestId !== contextId) {
124
+ // 컨텍스트가 변경되었으면 원본 콜백 실행
125
+ // eslint-disable-next-line prefer-spread
126
+ callback.apply(null, args);
127
+ return;
128
+ }
129
+ if (abortSignal.aborted) {
130
+ throw new Error(`REQUEST_ABORTED: setTimeout 콜백이 중단되었습니다 (${contextId})`);
131
+ }
132
+ // eslint-disable-next-line prefer-spread
133
+ callback.apply(null, args);
134
+ };
135
+ const timerId = this.originalSetTimeout(wrappedCallback, delay, ...args);
136
+ // 중단 이벤트 리스너 등록
137
+ const abortHandler = () => {
138
+ clearTimeout(timerId);
139
+ };
140
+ abortSignal.addEventListener('abort', abortHandler, { once: true });
141
+ return timerId;
142
+ };
40
143
  }
41
144
  static unpatch() {
42
145
  if (!this.isPatched) {
43
146
  return;
44
147
  }
45
148
  global.Promise = this.originalPromise;
149
+ global.setTimeout = this.originalSetTimeout;
46
150
  this.isPatched = false;
47
151
  }
48
152
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolo-croket-dev/core",
3
- "version": "1.7.31",
3
+ "version": "1.7.32-slowquery.1",
4
4
  "author": "Yolo Co., Ltd.",
5
5
  "description": "Yolo commonization module",
6
6
  "main": "index.js",