【问题标题】:Best practices to handle exception in SailsJSSailsJS 中处理异常的最佳实践
【发布时间】:2015-02-13 13:40:17
【问题描述】:

我几天前才开始试用 SailsJS。
我已经意识到,只要有未捕获的异常,节点就会终止。
我有一个控制器列表,每个控制器在 services/ 中调用一个特定的服务 JS 文件(包含逻辑和数据库调用)。
我可以为所有服务编写一个全局错误处理程序,以便这些服务发生的任何类型的错误都应该由它处理,并且必须将适当的错误响应传达给前端。

我尝试使用 process.on('uncaughtexception') 或一些基本异常,但需要将其添加到每个服务方法中。

对于从客户端到服务器进行的所有服务调用,我还可以有一个共同点,所有 io.socket.post() 和 io..socket.get() 都通过该点

如果有任何指针/文章向我展示在 SailsJS 中处理未捕获异常和使用更短代码而不是在所有服务中编写冗余代码的常见最佳实践,我将不胜感激。

【问题讨论】:

  • 非常好的问题。以前从未想过这一点,但策略是在调用控制器操作之前执行的代码。您可能想尝试使用策略将控制器逻辑包装在 try catch 块中,并将该策略作为默认策略应用于所有控制器操作。我还没有尝试过,这只是我脑海中的一个随机想法。让我知道它是否有效。我以后可能会试一试
  • 这还不是真正的答案,但请留意zones - 除其他外,它解决了nodejs 中的错误处理问题。

标签: node.js exception-handling sails.js


【解决方案1】:

最佳做法是在控制器中使用Domains。这将处理异步代码中的异常,并且相对简单。

您可以使用trycatch 之类的东西来稍微简化一下,但基于域的异常将是最有效的。它将确保异常不会使您的应用程序崩溃。只需在您的控制器中创建一个新域并在该域内运行您的控制器方法。

Sailsjs 基于 express 你可以使用连接中间件,并且你可以从中间件无缝创建一个新的域。有express-domain-middleware之类的东西。这可能是最美观、最方便的选择。

更新: 正如 Benjamin Gruenbaum 所提到的,Domains 计划在节点 v1 中被弃用。也许你应该仔细阅读 Joyents Error Handling Best Practices。它与您正在使用的框架无关。

此外,您仍然可以使用域,但没有办法全局处理 node.js 中的错误。一旦弃用,您总是可以相对容易地消除对域的依赖。也就是说,最好不要仅仅依赖域。

Strongloop 还提供了一个受 Zone 域启发的库。这也是一种选择。

【讨论】:

  • 域可能会在不久的将来被弃用。 github.com/iojs/io.js/issues/66
  • 定义“近期”,v0.11 甚至没有确定的发布日期,而且 v0.12 至少还要再过一年才能看到,这是乐观的。 AFAIK v1 甚至还没有被开发出来,到目前为止它只是一个想法。它甚至提到域可能会被移动到一个包(核心之外)以保持向后兼容性。如果您使用建议的中间件,那么您可以轻松地替换您的异常处理。
  • 到不久的将来是~一个月。 Node 最近被分叉到 io.js 并且大多数核心贡献者已经迁移(因为发布周期)。我说不推荐使用没有删除。
  • 我更新了我的答案以反映您的批评。我相信域仍然是一种选择,因为我们可能在一段时间内不会看到域被弃用,由于您提到的原因,它们可能不是“最佳实践”。也就是说,很难为处理异常提供“适合所有人”的最佳实践。我会推荐我的回答中提供的 Joyents 指南,作为了解如何开发容错应用程序的良好指南。
【解决方案2】:

由于编程错误而让节点实例出错是可以的,否则它可能会继续处于不一致的状态和混乱的业务逻辑。在生产环境中,服务器可以在崩溃时重新启动,如果错误不频繁,这将重置其状态并使其保持可用。在所有这一切中,记录所有内容非常重要。这适用于大多数 Node 设置,包括 SailsJS。

可以采取以下方法:

  1. 使用记录器:服务器组件应该可以访问专用记录器。应该连接到通知开发人员(电子邮件?)非常严重的错误的服务。
  2. 将每个请求的错误传播到最后:小心地转发请求处理中任何步骤的错误。在基于 ExperssJs/ConnectJs/middle-ware 的设置中,next(err) 可用于将错误传递给中间件链。在链的末尾捕获中间件的错误将得到这个错误,将其详细记录,并返回 500 状态。您可以使用DomainsZonesPromisesasync 或任何您喜欢的方式来处理请求和捕获错误。
  3. process.on('uncaughtexception') 上关闭:记录错误,进行必要的清理,然后再次向关闭进程抛出相同的错误。
  4. Linux 上的用户 PM2/Forever 或 Upstart/init.d:现在,当进程因错误异常而关闭时,这些工具将重新启动它并跟踪服务器崩溃的时间。如果服务器崩溃的时间过长,最好停止它并立即采取行动。

【讨论】:

  • Upstart/init.d 将是您第四条建议的一个很好的扩展。如果服务器意外重新启动,则永远无法重新启动应用程序。 PM2 为这个问题提供了解决方案,但是 PM2 需要节点 v0.11 才能有效工作,并且在 v0.10 或更低版本上可能会出现意外行为,因为它依赖于 experimental 核心模块。
  • @tsturzl 谢谢。已更新答案。
【解决方案3】:

我还没有尝试过,但我相信您应该能够使用 process.on('uncaughtexception') 在 bootstrap.js 中设置一个包罗万象的异常处理程序。

就我个人而言,我通过bluebird 库使用承诺,并放置一个将所有错误传递给全局错误处理函数的catch 语句。

【讨论】:

  • 我没有反对,但这是非常糟糕的做法,因为您的应用程序在某处发出未处理的异常。这是惰性错误处理,任何时候建议任何人,您都必须同时停止并重新启动进程,并且您应该尝试继续您正在做的事情(上传,写入文件,数据库通信等)。您必须停止一切并重新启动节点进程。
  • 我假设您指的是非承诺解决方案,我真的应该以“嘿,你可以这样做,但不要这样做”作为开头。
  • 不是真的,我也不是故意要攻击你——但是编写带有未捕获异常的代码只是不好的做法,并且像这样在应用程序的“顶部”捕获它只是懒惰。在这些情况下,大多数服务器不需要您重新启动服务器进程。节点可以。如果您捕获异常并且不重新启动进程,节点可能会陷入“未知状态”(如果我没记错的话,文档是这样说的)。
  • 别抱歉,我说过我从来没有亲自这样做过,所以我不知道后果,甚至不知道它是如何真正起作用的。
  • 这不是处理异常,而是选择不处理异常。这个想法是利用错误或异常。这是一种无知的做法。
猜你喜欢
  • 2018-01-03
  • 1970-01-01
  • 1970-01-01
  • 2017-05-11
  • 2013-05-09
  • 2011-11-10
  • 1970-01-01
  • 2013-04-22
相关资源
最近更新 更多