@quark-fw/plugin-threads 0.1.15 → 0.1.16
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/package.json +6 -6
- package/src/index.ts +26 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quark-fw/plugin-threads",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"types": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -21,16 +21,16 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@quark-fw/atom": "0.1.
|
|
25
|
-
"@quark-fw/plugin": "0.1.
|
|
26
|
-
"@quark-fw/plugin-env": "0.1.
|
|
27
|
-
"@quark-fw/plugin-redis": "0.1.
|
|
24
|
+
"@quark-fw/atom": "0.1.16",
|
|
25
|
+
"@quark-fw/plugin": "0.1.16",
|
|
26
|
+
"@quark-fw/plugin-env": "0.1.16",
|
|
27
|
+
"@quark-fw/plugin-redis": "0.1.16",
|
|
28
28
|
"chokidar": "^5.0.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"ioredis": "^5.9.3"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@quark-fw/core": "0.1.
|
|
34
|
+
"@quark-fw/core": "0.1.16"
|
|
35
35
|
}
|
|
36
36
|
}
|
package/src/index.ts
CHANGED
|
@@ -38,6 +38,19 @@ await quark.registerPlugin({
|
|
|
38
38
|
const handles = new Map<string, WorkerHandle[]>();
|
|
39
39
|
// "file#instance" -> число рестартов подряд
|
|
40
40
|
const restarts = new Map<string, number>();
|
|
41
|
+
// "file#instance" -> отложенный рестарт упавшего инстанса. Упавший
|
|
42
|
+
// инстанс уже убран из handles, поэтому stop() его не видит — без
|
|
43
|
+
// отмены таймера остановленный (или удалённый) воркер воскресал, а
|
|
44
|
+
// stop+spawn при правке файла давали дубль инстанса.
|
|
45
|
+
const pendingRestarts = new Map<string, NodeJS.Timeout>();
|
|
46
|
+
const cancelRestarts = (file: string) => {
|
|
47
|
+
for (const [key, timer] of pendingRestarts) {
|
|
48
|
+
if (!key.startsWith(`${file}#`)) continue;
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
pendingRestarts.delete(key);
|
|
51
|
+
restarts.delete(key);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
41
54
|
|
|
42
55
|
const updateList = () => {
|
|
43
56
|
list.value = [...handles.values()].flat().map((h) => ({
|
|
@@ -104,11 +117,13 @@ await quark.registerPlugin({
|
|
|
104
117
|
restarts.set(key, n + 1);
|
|
105
118
|
const delay = Math.min(1000 * 2 ** n, RESTART_MAX_DELAY_MS);
|
|
106
119
|
|
|
107
|
-
setTimeout(() => {
|
|
120
|
+
const timer = setTimeout(() => {
|
|
121
|
+
pendingRestarts.delete(key);
|
|
108
122
|
if (destroyed) return;
|
|
109
123
|
quark.ee.value.emit("thread:restart", file, instance);
|
|
110
124
|
forkInstance(file, instance);
|
|
111
125
|
}, delay).unref();
|
|
126
|
+
pendingRestarts.set(key, timer);
|
|
112
127
|
});
|
|
113
128
|
};
|
|
114
129
|
|
|
@@ -117,11 +132,19 @@ await quark.registerPlugin({
|
|
|
117
132
|
handle.stopping = true;
|
|
118
133
|
if (handle.child.exitCode !== null) return resolve();
|
|
119
134
|
|
|
135
|
+
// SIGTERM после таймаута, SIGKILL — если и его проигнорировали:
|
|
136
|
+
// иначе stop() и выключение приложения висели бы вечно
|
|
137
|
+
let killTimer: NodeJS.Timeout | undefined;
|
|
120
138
|
const timeout = setTimeout(() => {
|
|
121
139
|
handle.child.kill();
|
|
140
|
+
killTimer = setTimeout(
|
|
141
|
+
() => handle.child.kill("SIGKILL"),
|
|
142
|
+
SHUTDOWN_TIMEOUT_MS,
|
|
143
|
+
);
|
|
122
144
|
}, SHUTDOWN_TIMEOUT_MS);
|
|
123
145
|
handle.child.once("exit", () => {
|
|
124
146
|
clearTimeout(timeout);
|
|
147
|
+
clearTimeout(killTimer);
|
|
125
148
|
resolve();
|
|
126
149
|
});
|
|
127
150
|
try {
|
|
@@ -135,11 +158,13 @@ await quark.registerPlugin({
|
|
|
135
158
|
list,
|
|
136
159
|
async spawn(file) {
|
|
137
160
|
const abs = path.resolve(file);
|
|
161
|
+
cancelRestarts(abs);
|
|
138
162
|
if ((handles.get(abs) ?? []).length) return;
|
|
139
163
|
forkInstance(abs, 0);
|
|
140
164
|
},
|
|
141
165
|
async stop(file) {
|
|
142
166
|
const abs = path.resolve(file);
|
|
167
|
+
cancelRestarts(abs);
|
|
143
168
|
const all = handles.get(abs) ?? [];
|
|
144
169
|
await Promise.all(all.map(stopHandle));
|
|
145
170
|
handles.delete(abs);
|