Ragesh
Ragesh

Reputation: 3073

Why does node complain about unclosed file descriptors even though I'm closing all my handles?

I have an async function that creates a read stream and writes it to an http response, like so:

    let handle = await getFile();
    let stream = handle.createReadStream();
    let stat = await handle.stat();
    res.setHeader("content-length", stat.size);
    res.setHeader("content-type", "application/octet");
    res.statusCode = 200;
    stream.pipe(res);
    stream.on('close', () => {
      handle.close();
      res.end();
    });

As you can see, I close the handle when my stream is closed, and also end the response for good measure. Yet, I see node logging this occasionally:

(node:54119) Warning: Closing file descriptor 21 on garbage collection
(Use `node --trace-warnings ...` to show where the warning was created)
(node:54119) [DEP0137] DeprecationWarning: Closing a FileHandle object on garbage collection is deprecated. Please close FileHandle objects explicitly using FileHandle.prototype.close(). In the future, an error will be thrown if a file descriptor is closed during garbage collection.

There are no errors in my HTTP responses and I have verified with a log that my handle.close() is getting called for every request. Why does node think that I have unclosed file descriptors?

Upvotes: 0

Views: 359

Answers (2)

Nick
Nick

Reputation: 1

I had a similar issue, and on checking the types, I found that handle.close() returns a Promise. So even awaiting on handle.close() is also a valid approach.

let handle = await getFile();
let stream = handle.createReadStream();
let stat = await handle.stat();

res.setHeader("content-length", stat.size);
res.setHeader("content-type", "application/octet");
res.statusCode = 200;
stream.pipe(res);
stream.on('close', async () => {
  await handle.close();
  res.end();
});

Upvotes: 0

Ragesh
Ragesh

Reputation: 3073

It was because my async function was returning before the stream was done writing. I fixed it by wrapping it with a promise and awaiting it:

    let handle = await getFile();
    let stream = handle.createReadStream();
    let stat = await handle.stat();
    res.setHeader("content-length", stat.size);
    res.setHeader("content-type", "application/octet");
    res.statusCode = 200;
    await new Promise<void>((resolve, reject) => {
        stream.pipe(res);
        stream.on('close', () => {
          handle.close();
          res.end();
          resolve();
        });
    });

Upvotes: 0

Related Questions