fs.unlinkSync 在 Sails 上的 Grunt 错误

Grunt error with fs.unlinkSync on Sails

我正在使用 skipper 接收文件,使用 sharp 调整大小(并保存)并使用 fs unlink 删除旧图像。但是这次我遇到了一个非常奇怪的错误,这让我很担心:

error: ** Grunt :: An error occurred. ** error: Aborted due to warnings. Running "copy:dev" (copy) task Warning: Unable to read "assets/images/users/c8e303ca-1036-4f52-88c7-fda7e01b6bba.jpg" file (Error code: ENOENT).

error: Looks like a Grunt error occurred-- error: Please fix it, then restart Sails to continue running tasks (e.g. watching for changes in assets) error: Or if you're stuck, check out the troubleshooting tips below.

error: Troubleshooting tips: error: error: *-> Are "grunt" and related grunt task modules installed locally? Run npm install if you're not sure. error: error: *-> You might have a malformed LESS, SASS, CoffeeScript file, etc. error: error: *-> Or maybe you don't have permissions to access the .tmp directory? error: e.g., (edited for privacy)/sails/.tmp ? error: error: If you think this might be the case, try running: error: sudo chown -R 1000 (edited for privacy)/sails/.tmp

Grunt 停止了 运行 并且在生产中使用它是一个很大的禁忌......我相信这是由于 fs.unlinkSync(fname) 的并发造成的。该错误也是间歇性的,并且在某些机器上很难重现(也许是 IO ops/sec?)。

我有以下控制器操作:

var id = 1; // for example

req.file('avatar').upload({
    dirname: require('path').resolve(sails.config.appPath, 'assets/images')
}, function(err, files){
    var avatar = files.pop();

    //file name operations here. output is defined as the path + id + filetype
   //...

    sharp(avatar.fd)
    .resize(800, 800)
    .toFile(output, (err, info)=>{
        if(err){
            res.badRequest();
        } else {
            fs.unlinkSync(avatar.fd);
            res.ok();
        }
    });
});

现在我一直在思考几个解决方案:

  1. 将新图片直接输出到.temp
  2. .tmp 上存在文件时取消链接。解释:Grunt 已经复制了旧文件,所以删除它是安全的!

但我不知道这是否是一些意大利面条代码,或者是否存在更好的解决方案。

编辑:按照 arbuthnott 的建议,我的解决方案是像这样包装一个控制器:

get : function(req, res){
    var filepath = req.path.slice(1,req.path.length);
    //remove '/' root identifier. path.resolve() could be used

    if(fs.existsSync(path.resolve(filepath))){
        return res.sendfile(filepath);
    } else {
        return res.notFound();  
    }
}

我认为您对错误的看法是正确的。您正在对 assets 文件夹进行一些快速更改。如果我没看错你的代码:

  1. 将带有用户生成文件名的图像添加到 assets/images(例如 cat.jpg
  2. Copy/resize 文件到 assets/images 中的 id 文件名(例如 abc123.jpg
  3. 删除原上传(cat.jpg)

(我不知道 sharp 的细节,那里可能还有更多内容)

如果 sails 运行 处于开发模式,那么 Grunt 将尝试监视整个 assets/ 文件夹,并将所有更改复制到 .tmp/public/。很容易想象 Grunt 可能会注册一个更改,但是当它开始复制添加的文件时 (assets/images/cat.jpg) 它已经消失了。


我有两个解决方案的建议:

一个:

按照您的建议,将您的原件上传到 .tmp 文件夹(甚至可以是 .tmp 的自定义子文件夹)。仍然将您的尺寸副本放入 /assets/images/,它将被复制到 /.tmp/public/,运行 应用程序可以将其作为资产访问。但是 Grunt 将忽略 .tmp 文件夹中的快速添加然后删除。

两个:

对您希望包含在版本控制中的内容以及您希望在生产中成为 运行 的 Grunt 任务做一些一般性的思考。请注意,如果您使用 sails lift --prod,则默认情况下 Grunt watch 是关闭的,甚至不会出现此错误。一般来说,我不觉得我们希望 Grunt 在生产中做太多,它更像是一条开发捷径。具体来说,Grunt watch 会在生产服务器上使用大量资源。

关于版本控制的注意事项只是您可能希望 assets/images/ 的某些内容在版本控制中(站点使用的图像等),但在用户的情况下可能不是-上传的头像。确保你有办法区分这些内容(子目录或其他)。然后他们可以很容易地 .git-ignore' 或任何合适的。

希望对您有所帮助,祝您好运!