'use strict'; // A worker may own both a fixture and a production server. Signal cleanup must // finish all server shutdowns before removing the fixture directory or exiting. const resources = []; let installed = false; let exiting; function registerResource(stop, emergencyStop, phase = 0) { const resource = { stop, emergencyStop, phase }; resources.push(resource); if (!installed) { process.on('exit', emergencyCleanup); process.on('SIGINT', interrupted); process.on('SIGTERM', interrupted); installed = true; } return () => { const index = resources.indexOf(resource); if (index !== -1) resources.splice(index, 1); if (resources.length === 0 && installed) { process.removeListener('exit', emergencyCleanup); process.removeListener('SIGINT', interrupted); process.removeListener('SIGTERM', interrupted); installed = false; } }; } function emergencyCleanup() { for (const resource of [...resources].sort((a, b) => b.phase - a.phase)) { resource.emergencyStop(); } } function interrupted() { if (exiting) return; exiting = (async () => { // Production children have higher phase and stop before fixture cleanup. for (const phase of [...new Set(resources.map((resource) => resource.phase))].sort((a, b) => b - a)) { await Promise.allSettled(resources.filter((resource) => resource.phase === phase).map((resource) => resource.stop())); } process.exit(130); })(); } module.exports = { registerResource };