@vrdmr/fnx-test 0.1.2 → 0.2.0

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/lib/cli.js CHANGED
@@ -12,7 +12,8 @@ function isPortFree(port) {
12
12
  return new Promise((resolve) => {
13
13
  const srv = createServer();
14
14
  srv.once('error', () => resolve(false));
15
- srv.listen(port, '127.0.0.1', () => { srv.close(() => resolve(true)); });
15
+ // Host binds 0.0.0.0, so check that address (catches both IPv4 wildcard and loopback)
16
+ srv.listen(port, '0.0.0.0', () => { srv.close(() => resolve(true)); });
16
17
  });
17
18
  }
18
19
 
@@ -360,14 +360,24 @@ export async function launchHost(hostDir, opts) {
360
360
 
361
361
  const filter = createLogFilter(verbose, hostState);
362
362
 
363
+ // Start host in its own process group so we can kill it + all child workers together
363
364
  const child = spawn(hostExe, [], {
364
365
  env,
365
366
  stdio: ['inherit', 'pipe', 'pipe'],
366
367
  cwd: opts.scriptRoot,
368
+ detached: true, // creates new process group (pgid = child.pid)
367
369
  });
368
370
 
369
371
  hostState.pid = child.pid;
370
372
 
373
+ // Kill the entire process group (host + Python/Node workers it spawns)
374
+ function killHostGroup(signal) {
375
+ try { process.kill(-child.pid, signal); } catch { /* already dead */ }
376
+ }
377
+
378
+ // Ensure the host process group is killed if Node exits unexpectedly
379
+ process.on('exit', () => killHostGroup('SIGKILL'));
380
+
371
381
  // Process stdout and stderr through the log filter
372
382
  for (const stream of [child.stdout, child.stderr]) {
373
383
  const rl = createInterface({ input: stream });
@@ -382,18 +392,21 @@ export async function launchHost(hostDir, opts) {
382
392
  });
383
393
  }
384
394
 
385
- process.on('SIGINT', () => {
395
+ function cleanup(signal) {
386
396
  stopAzurite();
387
- child.kill('SIGINT');
397
+ killHostGroup(signal);
388
398
  if (hostState._mcpServer) hostState._mcpServer.close();
389
- setTimeout(() => process.exit(0), 500);
390
- });
391
- process.on('SIGTERM', () => {
392
- stopAzurite();
393
- child.kill('SIGTERM');
394
- if (hostState._mcpServer) hostState._mcpServer.close();
395
- setTimeout(() => process.exit(0), 500);
396
- });
399
+ // Give the host 2s to shut down gracefully, then force kill the group
400
+ const forceTimer = setTimeout(() => {
401
+ killHostGroup('SIGKILL');
402
+ process.exit(0);
403
+ }, 2000);
404
+ forceTimer.unref();
405
+ child.once('exit', () => process.exit(0));
406
+ }
407
+
408
+ process.on('SIGINT', () => cleanup('SIGINT'));
409
+ process.on('SIGTERM', () => cleanup('SIGTERM'));
397
410
 
398
411
  return new Promise((resolve, reject) => {
399
412
  child.on('error', (err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrdmr/fnx-test",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "SKU-aware Azure Functions local emulator",
5
5
  "type": "module",
6
6
  "bin": {