@vercube/devkit 0.0.47 → 0.0.48

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.
Files changed (2) hide show
  1. package/dist/index.mjs +28 -12
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -226,29 +226,47 @@ function createDevServer(app) {
226
226
  let reloadPromise;
227
227
  let currentFork;
228
228
  /**
229
+ * Terminates a worker and resolves only once it has fully exited, so the
230
+ * resources it owns (the HTTP port and any message-queue consumers) are
231
+ * released before a replacement is spawned.
232
+ *
233
+ * A graceful SIGTERM may not stop a worker that holds long-lived handles —
234
+ * e.g. an open message-queue connection keeps the event loop alive — so fall
235
+ * back to SIGKILL after a short grace period.
236
+ * @param {ChildProcess} worker - The worker process to terminate.
237
+ * @returns {Promise<void>} A promise that resolves when the worker has exited.
238
+ */
239
+ function killWorker(worker) {
240
+ if (worker.exitCode !== null || worker.signalCode !== null) return Promise.resolve();
241
+ return new Promise((resolve) => {
242
+ const killTimer = setTimeout(() => worker.kill("SIGKILL"), 1e3);
243
+ worker.once("exit", () => {
244
+ clearTimeout(killTimer);
245
+ resolve();
246
+ });
247
+ worker.kill("SIGTERM");
248
+ });
249
+ }
250
+ /**
229
251
  * Reloads the fork by killing the old one and creating a new one.
230
252
  * @returns {Promise<void>} A promise that resolves when the fork is reloaded.
231
253
  */
232
254
  async function _reload() {
233
255
  const oldFork = currentFork;
234
256
  currentFork = void 0;
235
- if (oldFork) await new Promise((resolve) => {
236
- const killTimer = setTimeout(() => oldFork.kill("SIGKILL"), 1e3);
237
- oldFork.once("exit", () => {
238
- clearTimeout(killTimer);
239
- resolve();
240
- });
241
- oldFork.kill("SIGTERM");
242
- });
257
+ if (oldFork) await killWorker(oldFork);
243
258
  currentFork = fork(forkEntry);
244
- if (!currentFork) return;
245
259
  }
246
260
  /**
247
261
  * Reloads the fork.
262
+ *
263
+ * Reloads are serialized: overlapping file-change events chain onto the
264
+ * previous reload instead of running concurrently, which would otherwise
265
+ * spawn a second worker while another is still shutting down.
248
266
  * @returns {Promise<void>} A promise that resolves when the worker is reloaded.
249
267
  */
250
268
  const reload = () => {
251
- reloadPromise = _reload().then(() => {
269
+ reloadPromise = (reloadPromise ?? Promise.resolve()).then(() => _reload()).then(() => {
252
270
  consola.success({
253
271
  tag: "worker",
254
272
  message: "Worker reloaded successfully"
@@ -259,8 +277,6 @@ function createDevServer(app) {
259
277
  message: "Failed to reload worker",
260
278
  error
261
279
  });
262
- }).finally(() => {
263
- reloadPromise = void 0;
264
280
  });
265
281
  return reloadPromise;
266
282
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercube/devkit",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "description": "Devkit module for Vercube framework",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  "pathe": "2.0.3",
35
35
  "rolldown": "1.0.2",
36
36
  "unplugin-isolated-decl": "0.16.0",
37
- "@vercube/core": "0.0.47"
37
+ "@vercube/core": "0.0.48"
38
38
  },
39
39
  "publishConfig": {
40
40
  "access": "public"