在 Express 请求中处理 Long I/O 操作的最佳实践

Posted

技术标签:

【中文标题】在 Express 请求中处理 Long I/O 操作的最佳实践【英文标题】:Best practice for handling Long I/O operation inside Express request 【发布时间】:2020-12-01 22:56:23 【问题描述】:

寻求有关在 Express 请求处理程序中处理长 I/O 操作的最佳模式的输入。具体来说,我会将上传的文件复制到 S3,但不需要完成 I/O 即可完成对请求的处理。 (注意:需要在服务器上有一个本地副本,所以直接上传到 S3 不是一个解决方案。)

我有一个可行的解决方案,可以将文件异步复制到 S3,但它不会在从请求返回之前等待复制完成。此解决方案没有明显问题。但是,这种方法似乎有缺陷,可能有更好的模式(我对 JS 比较陌生)。

我也可以将复制任务排队并在后台处理。但在添加更多代码之前,请检查我的担忧是否有效,或者按原样实施是否没有问题。

感谢任何见解。

编辑:添加显示模式的示例代码

/* Async handler because await on some other (not related to S3 copy)stuff to complete before returning (but must faster completion than the S3 copy */
app.get("/some/route", async (req, res) => 
    
    s3.upload(/* args */).then(() => 
        // log success
    ).catch((e) => 
        // log error
    )

    // A few lines of code
    res.status(200).send('Done');
    // We be done before s3.upload completes
);

【问题讨论】:

FWIW,如果代码中有其他地方使用await,最好保持一致并使用await(和try/catch)调用s3.upload也是。此外,当将async 函数传递给app.get 之类的函数时,它不会对它返回的承诺做任何事情,重要的是不要让函数拒绝它的承诺,例如将try/catch围绕整个函数体。 Node.js 当前处理未处理的拒绝,并警告它可能在将来的版本中在检测到它们时终止进程,这不是很好。 :-) 示例:pastebin.com/RuJk2eL1 您的代码当前正在做的是在后台处理复制任务并将该任务的完成排队 - 这正是您打算做的事情,但所有这些都由解释器为您处理。这就是事件循环的用途,但没有在代码中添加额外的麻烦来掩盖您保存文件并立即返回而无需等待的意图。 @slebetman,感谢您确认原样模式正常。我认为它被添加到节点等待所有承诺完成的事件队列中,但是模式“感觉”错误。关于对 S3 的调用,故意不等待它,因为不想阻塞 I/O 来完成,这是问题的症结所在。 【参考方案1】:

您上传文件(资源)的方法非常适合这种情况。

我会推荐以下内容以提高未来的可用性:

    在上传请求上生成资源的 UUID 并将其返回给用户(此 UUID 将允许用户管理资源)。使用202 Accepted 作为响应状态代码。 添加API查询资源状态。这将返回有关资源状态的信息,例如uploading | done | not_exsist (很高兴)添加 API 以中止上传 (很高兴)添加可以通知客户端资源状态的 WebSocket。

【讨论】:

以上是关于在 Express 请求中处理 Long I/O 操作的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

简单理解I/O模型

(服务运维)I/O流程和模型

Java I/O模型

对常用I/O模型进行比较说明

五种I/O模型的学习

如何在 Express 请求处理程序中编写非阻塞异步函数 [重复]