Deno.serve AbortController onError. How?
When I run my new Deno.serve() updated implementation I get a type error. Perhaps I'm doing it wrong. Maybe it is the way I am trying to use the Abort Controller or maybe the onError handler must always return something?
I get the following error:
// You can stop the server with an AbortSignal.
// The abort signal needs to be passed as the signal option in the options bag.
const ac = new AbortController();
const server = Deno.serve({
// The port to listen on.
port: config.http.server.port,
// A literal IP address or host name that can be resolved to an IP address.
hostname: "0.0.0.0",
// An AbortSignal to close the server and all connections.
signal: ac.signal,
// The callback which is called when the server starts listening.
onListen({ port, hostname }) {
// console.log(`Server started at http://${hostname}:${port}`);
console.log(
`%cApplication..... fsrv v2.0 - A Deno HTTP Server
Deno v${Deno.version.deno} : Typescript v${Deno.version.typescript} : V8 v${Deno.version.v8}
Gateway URL..... http://${hostname}:${port}
Server Root..... ${pathJoin(CWD, config.http.server.www)}
Internal Pages.. ${pathJoin(CWD, config.http.server.internal)}
Site Root....... ${pathJoin(CWD, config.http.server.public)}`,
"color: #7986cb",
);
},
// The handler to invoke when route handlers throw an error.
onError(error) {
console.error(error);
log("HTTP 500");
// FATAL ERROR!
// The server aborts when the abort signal is sent to the abort controller.
console.log("Closing server...");
ac.abort();
// To wait for the server to close, await the promise returned from the Deno.serve API.
server.finished.then(() => console.log("Server closed"));
},
}, handler);
// You can stop the server with an AbortSignal.
// The abort signal needs to be passed as the signal option in the options bag.
const ac = new AbortController();
const server = Deno.serve({
// The port to listen on.
port: config.http.server.port,
// A literal IP address or host name that can be resolved to an IP address.
hostname: "0.0.0.0",
// An AbortSignal to close the server and all connections.
signal: ac.signal,
// The callback which is called when the server starts listening.
onListen({ port, hostname }) {
// console.log(`Server started at http://${hostname}:${port}`);
console.log(
`%cApplication..... fsrv v2.0 - A Deno HTTP Server
Deno v${Deno.version.deno} : Typescript v${Deno.version.typescript} : V8 v${Deno.version.v8}
Gateway URL..... http://${hostname}:${port}
Server Root..... ${pathJoin(CWD, config.http.server.www)}
Internal Pages.. ${pathJoin(CWD, config.http.server.internal)}
Site Root....... ${pathJoin(CWD, config.http.server.public)}`,
"color: #7986cb",
);
},
// The handler to invoke when route handlers throw an error.
onError(error) {
console.error(error);
log("HTTP 500");
// FATAL ERROR!
// The server aborts when the abort signal is sent to the abort controller.
console.log("Closing server...");
ac.abort();
// To wait for the server to close, await the promise returned from the Deno.serve API.
server.finished.then(() => console.log("Server closed"));
},
}, handler);
error: TS2322 [ERROR]: Type '(error: unknown) => void' is not assignable to type '(error: unknown) => Response | Promise<Response>'.
Type 'void' is not assignable to type 'Response | Promise<Response>'.
onError(error) {
error: TS2322 [ERROR]: Type '(error: unknown) => void' is not assignable to type '(error: unknown) => Response | Promise<Response>'.
Type 'void' is not assignable to type 'Response | Promise<Response>'.
onError(error) {
3 Replies
That's because
at the end of the
onError
needs a return value. Although never called because of the ac.abort()
call, just add return new Response("never");
return new Response("never");
onError
function.Technically a
reason
should be passed to AbortController.abort('Stream aborted')
so that reason can be propagated to abort()
methods and/or catch()
/catch (e) {}
.Thank you both for such simple solutions. I now have 2 working example scenarios.
Scenario #1
* Once started, the server runs regardless of encountering route handler errors.
*
Scenario #2
* Once started, the server runs until the first error is thrown by the route handlers.
*
onError
, a warning HTTP 500 response is still returned to the client.
* There is no Abort Controller.
Deno.serve({
// The port to listen on.
port: config.http.server.port,
// A literal IP address or host name that can be resolved to an IP address.
hostname: "0.0.0.0",
// The callback which is called when the server starts listening.
onListen({ port, hostname }) {
console.log(
`%cApplication..... fsrv v2.0 - A Deno HTTP Server
Deno v${Deno.version.deno} : Typescript v${Deno.version.typescript} : V8 v${Deno.version.v8}
Permissions: --allow-sys --allow-read --allow-net
Gateway URL..... http://${hostname}:${port}
Server Root..... ${config.http.server.www}
Internal Pages.. ${config.http.server.internal}
Site Root....... ${config.http.server.public}\n\n`,
"color: #7986cb",
);
},
// The handler to invoke when route handlers throw an error.
onError(error: unknown) {
console.error(error);
console.log("HTTP 500");
// WARNING!
/**
* onError returns HTTP response.
* Server proceeds to next request.
*
*/
return serverResponse(
"HTTP 500: Internal Server Error",
500,
"text/plain",
);
},
}, handler); // <-- The handler goes here
Deno.serve({
// The port to listen on.
port: config.http.server.port,
// A literal IP address or host name that can be resolved to an IP address.
hostname: "0.0.0.0",
// The callback which is called when the server starts listening.
onListen({ port, hostname }) {
console.log(
`%cApplication..... fsrv v2.0 - A Deno HTTP Server
Deno v${Deno.version.deno} : Typescript v${Deno.version.typescript} : V8 v${Deno.version.v8}
Permissions: --allow-sys --allow-read --allow-net
Gateway URL..... http://${hostname}:${port}
Server Root..... ${config.http.server.www}
Internal Pages.. ${config.http.server.internal}
Site Root....... ${config.http.server.public}\n\n`,
"color: #7986cb",
);
},
// The handler to invoke when route handlers throw an error.
onError(error: unknown) {
console.error(error);
console.log("HTTP 500");
// WARNING!
/**
* onError returns HTTP response.
* Server proceeds to next request.
*
*/
return serverResponse(
"HTTP 500: Internal Server Error",
500,
"text/plain",
);
},
}, handler); // <-- The handler goes here
onError
, the abort signal is sent to the AbortController
.
* The abort signal needs to be passed as the signal option in the options bag.
const ac = new AbortController();
const server = Deno.serve({
// The port to listen on.
port: config.http.server.port,
// A literal IP address or host name that can be resolved to an IP address.
hostname: "0.0.0.0",
// An AbortSignal to close the server and all connections.
signal: ac.signal,
// The callback which is called when the server starts listening.
onListen({ port, hostname }) {
// console.log(`Server started at http://${hostname}:${port}`);
console.log(
`%cApplication..... fsrv v2.0 - A Deno HTTP Server
Deno v${Deno.version.deno} : Typescript v${Deno.version.typescript} : V8 v${Deno.version.v8}
Gateway URL..... http://${hostname}:${port}
Server Root..... ${config.http.server.www}
Internal Pages.. ${config.http.server.internal}
Site Root....... ${config.http.server.public}`,
"color: #7986cb",
);
},
// The handler to invoke when route handlers throw an error.
onError(error: unknown) {
console.error(error);
log("HTTP 500");
// FATAL ERROR!
// The server aborts when the abort signal is sent to the abort controller.
console.log("Closing server...");
// Send the abort signal!
ac.abort("Stream aborted");
// To wait for the server to close, await the promise returned from the Deno.serve API.
server.finished.then(() => console.log("Server closed"));
/**
* onError needs a return value or error Type 'void' is not assignable
* to type 'Response | Promise<Response>' occurs.
*
* return here is NEVER reached because of the ac.abort() call that preceeds it.
*
*/
return new Response("Stream aborted");
},
}, handler); // <-- The handler goes here
const ac = new AbortController();
const server = Deno.serve({
// The port to listen on.
port: config.http.server.port,
// A literal IP address or host name that can be resolved to an IP address.
hostname: "0.0.0.0",
// An AbortSignal to close the server and all connections.
signal: ac.signal,
// The callback which is called when the server starts listening.
onListen({ port, hostname }) {
// console.log(`Server started at http://${hostname}:${port}`);
console.log(
`%cApplication..... fsrv v2.0 - A Deno HTTP Server
Deno v${Deno.version.deno} : Typescript v${Deno.version.typescript} : V8 v${Deno.version.v8}
Gateway URL..... http://${hostname}:${port}
Server Root..... ${config.http.server.www}
Internal Pages.. ${config.http.server.internal}
Site Root....... ${config.http.server.public}`,
"color: #7986cb",
);
},
// The handler to invoke when route handlers throw an error.
onError(error: unknown) {
console.error(error);
log("HTTP 500");
// FATAL ERROR!
// The server aborts when the abort signal is sent to the abort controller.
console.log("Closing server...");
// Send the abort signal!
ac.abort("Stream aborted");
// To wait for the server to close, await the promise returned from the Deno.serve API.
server.finished.then(() => console.log("Server closed"));
/**
* onError needs a return value or error Type 'void' is not assignable
* to type 'Response | Promise<Response>' occurs.
*
* return here is NEVER reached because of the ac.abort() call that preceeds it.
*
*/
return new Response("Stream aborted");
},
}, handler); // <-- The handler goes here