I simply run file_server, but it will start returning the error with 500 status.
deno 0.32.0
v8 8.1.108
typescript 3.7.2
deno run --allow-net --allow-read https://deno.land/std/http/file_server.ts .
This is the my test case.
const url = 'http://localhost:4500/public/index.html';
let count = 0;
(async () => {
while (true) {
console.log('opening...', ++count);
const res = await fetch(url);
if (res.status !== 200) {
console.log('error!.', res.status);
} else {
console.log('opened.', res.status);
}
}
})();
If I increase ulimit, the error can be delayed, but it won't fix the issue.
I have tested some cases, it seems files are not closed properly.
If I close files after returning responses, it won't cause the error.
async function serveFile(req: ServerRequest, filePath: string) {
const [file, fileInfo] = await Promise.all([open(filePath), stat(filePath)]);
const headers = new Headers();
headers.set('content-length', fileInfo.len.toString());
headers.set('content-type', 'text/plain; charset=utf-8');
const res = {
status: 200,
body: file,
headers,
};
return res;
}
window.onload = async function main() {
const addr = '0.0.0.0:4500';
const server = serve(addr);
console.log(`HTTP server listening on http://${addr}/`);
for await (const req of server) {
const res = await serveFile(req, 'public/index.html');
await req.respond(res);
res.body.close(); // <- here
}
};
@suguru03 your findings that res.body.close() fixes the problem is correct. When fetch returns a response, the body of response is stored as Deno resource. Therefor body has to be consumed or closed manually.
There was a try to address this problem by @kevinkassimo in #2106, but it did not land.
I solved this issue in my code (which is based on https://deno.land/std/http/file_server.ts) by defining this type guard:
function isCloser(object: any): object is Deno.Closer {
return 'close' in object;
}
And then at the end of the finally block in listenAndServe:
if (isCloser(response.body)) {
response.body.close();
}
Most helpful comment
@suguru03 your findings that
res.body.close()fixes the problem is correct. Whenfetchreturns a response, the body of response is stored as Deno resource. Therefor body has to be consumed or closed manually.There was a try to address this problem by @kevinkassimo in #2106, but it did not land.