Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/windows-shutdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ export async function requestLocalShutdown({ port, token, fetchImpl = fetch, req
signal: AbortSignal.timeout(requestTimeoutMs),
});
} catch (error) {
// A timeout means something else answered (or nothing parsed); a refused
// connection means the app is not running.
return error?.name === "TimeoutError" || error?.name === "AbortError" ? "unavailable" : "not-running";
// Only a refused connection proves the app is not running. Timeouts,
// resets and other failures can come from a live app that answered
// badly; report unavailable so setup does not walk over it.
return error?.code === "ECONNREFUSED" || error?.cause?.code === "ECONNREFUSED" ? "not-running" : "unavailable";
}
if (reply.status !== 202) return "unavailable";
// The app quits after answering; wait for the port to stop responding.
Expand Down
8 changes: 7 additions & 1 deletion test/windows-shutdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import assert from "node:assert/strict";
import { requestLocalShutdown, STOP_EXIT } from "../src/windows-shutdown.js";

test("a refused connection means the app is not running", async () => {
const outcome = await requestLocalShutdown({ port: 47832, token: "t", fetchImpl: async () => { throw new Error("fetch failed"); } });
const outcome = await requestLocalShutdown({ port: 47832, token: "t", fetchImpl: async () => { throw Object.assign(new Error("connect ECONNREFUSED"), { code: "ECONNREFUSED" }); } });
assert.equal(outcome, "not-running");
});

Expand Down Expand Up @@ -82,3 +82,9 @@ test('#815 a hanging health probe is not proof the listener stopped', async () =
assert.equal((await fetch(`http://127.0.0.1:${server.address().port}/`, { method: 'POST' })).status, 202);
} finally { server.closeAllConnections(); await new Promise(resolve => server.close(resolve)); }
});

test("a reset on the shutdown request is unavailable, not not-running (#1123)", async () => {
const reset = Object.assign(new Error("read ECONNRESET"), { code: "ECONNRESET" });
const outcome = await requestLocalShutdown({ port: 47832, token: "t", fetchImpl: async () => { throw reset; } });
assert.equal(outcome, "unavailable");
});
Loading