fix(http): remove unnecessary delay when closing server (#2732)

This commit is contained in:
Khaled Sakr 2022-10-04 17:22:56 +02:00 committed by GitHub
parent 7f7583139e
commit 385511bc43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 1 deletions

View File

@ -57,6 +57,7 @@ export class Server {
#handler: Handler;
#closed = false;
#listeners: Set<Deno.Listener> = new Set();
#acceptBackoffDelayAbortController = new AbortController();
#httpConnections: Set<Deno.HttpConn> = new Set();
#onError: (error: unknown) => Response | Promise<Response>;
@ -263,6 +264,8 @@ export class Server {
this.#listeners.clear();
this.#acceptBackoffDelayAbortController.abort();
for (const httpConn of this.#httpConnections) {
this.#closeHttpConn(httpConn);
}
@ -384,7 +387,16 @@ export class Server {
acceptBackoffDelay = MAX_ACCEPT_BACKOFF_DELAY;
}
await delay(acceptBackoffDelay);
try {
await delay(acceptBackoffDelay, {
signal: this.#acceptBackoffDelayAbortController.signal,
});
} catch (err: unknown) {
// The backoff delay timer is aborted when closing the server.
if (!(err instanceof DOMException && err.name === "AbortError")) {
throw err;
}
}
continue;
}

View File

@ -991,6 +991,44 @@ Deno.test(
},
);
Deno.test("Server should not leak async ops when closed", () => {
const hostname = "127.0.0.1";
const port = 4505;
const handler = () => new Response();
const server = new Server({ port, hostname, handler });
server.listenAndServe();
server.close();
// Otherwise, the test would fail with: AssertionError: Test case is leaking async ops.
});
Deno.test("Server should abort accept backoff delay when closing", async () => {
const hostname = "127.0.0.1";
const port = 4505;
const handler = () => new Response();
const rejectionError = new Deno.errors.NotConnected(
"test-socket-closed-error",
);
const rejectionCount = 1;
const conn = createMockConn();
const listener = new MockListener({
conn,
rejectionError,
rejectionCount,
});
const server = new Server({ port, hostname, handler });
server.serve(listener);
// Wait until the connection is rejected and the backoff delay starts.
await delay(0);
// Close the server, this should end the test without still having an active timer that would trigger an
// AssertionError: Test case is leaking async ops.
server.close();
});
Deno.test("Server should reject if the listener throws an unexpected error accepting a connection", async () => {
const conn = createMockConn();
const rejectionError = new Error("test-unexpected-error");