【问题标题】:NodeJS fs.unlink() not releasing file handlesNodeJS fs.unlink() 不释放文件句柄
【发布时间】:2018-01-30 19:22:56
【问题描述】:

我正在使用以下调用来删除我在 Linux (RHEL) 上运行的 nodeJS 应用程序中的现有文件。

fs.unlink(downloadsFolder + '/' + file)

但是,几天后我注意到文件仍在系统中,因为文件句柄没有释放。我重新启动了节点服务器,这些文件最终消失了。如何以编程方式解决此问题?

dzdo lsof -L | grep -i deleted

node  48782  root 600743243   403197165 /mnt/downloads/file_1516312894734.csv (deleted)
node  48782  root 14999       403197166 /mnt/downloads/file_1516729327306.csv (deleted)

我在fs.unlink() 的日志中也收到了这个警告,这会导致它吗?

(node:48782) [DEP0013] DeprecationWarning: Calling an asynchronous function without callback is deprecated.

【问题讨论】:

  • 您有没有找到解决文件被标记为已删除但仍占用空间的解决方案?下面的答案没有回答你的问题。
  • @ChadJohnson 不,仍在等待它,同时我每隔几天就会重新启动一次节点服务器以释放这些文件句柄。
  • 您是否尝试过截断这些文件?如果是,是否还需要重新启动服务器,如果是,为什么?打开文件句柄的允许数量是否有限制?
  • @ChadJohnson 如何截断文件?
  • 使用fs.truncate()。我是这样做的:fs.truncate(sourceFilePath, () => fs.unlink(sourceFilePath, () => {})); 所以,我在删除文件之前截断了它。这绝对是节省了一天。应该减轻您重新启动服务器的需要:)

标签: node.js linux


【解决方案1】:

正如警告所说,fs.unlink 方法是asynchronous,这意味着您必须提供一个回调函数,该函数将在删除操作完成时执行:

fs.unlink(downloadsFolder + '/' + file, (err) => {
    if (err) throw err;
    console.log('File successfully deleted');
});

或者你可以使用fs.unlink的同步版本:

fs.unlinkSync(downloadsFolder + '/' + file);

【讨论】:

  • 你是说提供回调函数实际上是释放文件句柄?
  • 文件句柄是什么意思?
  • 我想你回答了我关于回调警告的问题的第二部分,但是问题的第一部分是关于 fs.unlink() 将文件留在目录中并且 lsof 能够找到他们。它们被标记为已删除,但仍占用磁盘空间。
  • @YouneL 这没有回答问题。使用回调调用fs.unlink() 不会释放释放文件描述符的结果。正如@summerNight 在上面的评论中所说,文件被标记为已删除但仍占用空间。所以这个问题仍然没有答案。到目前为止,我发现的唯一解决方法是截断文件。
【解决方案2】:

我遇到了同样的问题,由于这个问题还没有合适的解决方案,所以我就是这样处理的;

就我而言,我更改了以下代码:

const uploaded = await s3.send(newPutObjectCommand({
        Bucket: `myBucketName-${module}`,
        Key: pusher === 'storage'
            ? user + '/' + filename
            : `${user}/${fName}`,
        Body: fileStream
    }));

对于这个:

const uploaded = ctx === 'p' 
    ? await s3.send(new PutObjectCommand({
        Bucket: `ek-knote-${module}`,
        Key: pusher === 'storage'
            ? user + '/' + filename
            : `${user}/${fName}`,
        Body: fileStream
    }))
    : {$metadata: {httpStatusCode: 200}};

然后就是那个错误出现的时候。

这段逻辑只将文件上传到 aws s3。唯一的区别是,当 ctx(上下文)具有值“p”(生产)时,下面的内容才会这样做。我以这种方式重写它,所以当我处于“d”(开发)中时,我实际上并没有上传文件(因为他们对使用的资源收取费用是坏事)。我发送的对象的主体有一个名为“fileStream”的常量。那只是一个读取流:

const fileStream = fs.createReadStream(fileRoute);

所以以前没有发生过。那么问题出在哪里?

由于某种原因,我不知道,当使用 fileStream const 时会以某种方式被破坏,但是当我跳过该部分时,一旦文件取消链接,get 仍然会挂在那里,直到服务器重新启动。我认为这是因为 const 被内存保留(因为您实际上无法通过右键单击并选择删除来删除它)但不要引用我的话;

所以我通过实际销毁来修复它,因为没有更好的词,fileStream:

    fork.on('close', async code => {

        obj.doc.destroy();

        await unlink(obj.file);

    });

obj 是我拥有的一个对象,其中包括文件路径(file)和实际的 readStream(doc)。只需在取消链接之前将其销毁即可解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 2011-12-04
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多