Bairdy
Bairdy12mo ago

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?
// 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);
I get the following 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) {
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
MrKleeblatt
MrKleeblatt12mo ago
That's because onError needs a return value. Although never called because of the ac.abort() call, just add
return new Response("never");
return new Response("never");
at the end of the onError function.
guest271314
guest27131412mo ago
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) {}.
Bairdy
Bairdy12mo ago
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. * 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
Scenario #2 * Once started, the server runs until the first error is thrown by the route handlers. * 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