【问题标题】:Capturing exceptions from event listeners in Symfony so that they don't stop other listeners从 Symfony 中的事件监听器捕获异常,这样它们就不会停止其他监听器
【发布时间】:2021-10-15 16:08:12
【问题描述】:

我在 Symfony 4.4 应用程序中遇到问题,其中有十几个侦听器正在侦听扩展 Symfony\Contracts\EventDispatcher\Event 的单个事件。问题是,如果其中一个监听器抛出异常,那么后面的监听器都不会被执行。

我一直在寻找一种方法来捕获侦听器的异常,以免发生这种情况。我尝试扩展 Symfony\Component\EventDispatcher\EventDispatcher 并覆盖 callListeners() 方法以包含 try/catch 以便我可以记录异常但继续执行。但我不知道如何告诉 Symfony 使用我的 EventDispatcher 而不是它自己的。

我不知道这是否是解决此问题的推荐方法。知道如何让它工作,或者是否有其他选择?

【问题讨论】:

  • @yivi 如果我们有异步事件处理,我们不会有问题,但我们还没有。但是每个听众都做不同的工作,应该完全独立于其他听众。并不是我们不希望出现问题时出现异常。只是一个侦听器中的异常不应阻止所有其他需要执行其任务的侦听器。例如,如果我们有一个订单事件和一个支付处理监听器和一个电子邮件通知监听器,那么支付处理不应该仅仅因为发送电子邮件通知出错而停止。
  • 再一次,看起来您正在使用事件调度程序来处理它不太适合的事情。考虑到您所描述的内容,您应该查看诸如 Symfony Messenger 或 Tactician 之类的东西并使用真正的异步处理,或者干脆不使用异常来控制事件调度程序侦听器中的流程。
  • 您通常可以通过添加编译器通道、获取服务定义然后设置新类来覆盖核心类。看看会发生什么样的意外副作用会很有趣。 stackoverflow.com/questions/62722129/…
  • 谢谢@Cerad,我会调查的!我理解@yivi 提到我们试图实现的目标可能是不寻常的,也许不值得推荐,但这就是我们目前所处的情况。目前我们决定尝试使用SimpleBus 及其处理事件EventBus 而不是 Symfony 的 EventDispatcher。原因是这使我们能够轻松地使用中间件来捕获和记录异常,而无需停止其余的侦听器。稍后我们将不得不重新考虑我们的方法,但现在这会奏效。

标签: php symfony error-handling symfony-eventdispatcher


【解决方案1】:

如果抛出异常,则应处理或停止执行。这就是例外的原因。

Event Dispatcher 组件并不意味着异步使用,具有完全解耦的侦听器。它被设计为同步执行,没有传输支持,所有侦听器都运行在同一个请求/执行线程上。

如果抛出异常并且未处理,则执行应该停止并且永远不会到达下一个侦听器。

即使您使用的是完全异步的解决方案,例如带有传输的 Symfony Messenger,抛出异常而不处理它也会阻止任何其他侦听器执行同一事件。

我认为您在工作中使用了错误的工具。

如果您不想停止执行,您的侦听器应该抛出异常。在监听器中处理异常,并利用机会记录等。

【讨论】:

  • 我理解你的意思,也许我使用了错误的工具来完成这项工作。但是我不知道我是否完全同意你的所有异常都应该在监听器中处理。这意味着将所有侦听器方法包装在 try {} catch(\Exception $e) {} 中,以确保没有意外错误会阻止其他重要的侦听器完成他们的工作。我也不知道我是否同意异步解决方案。例如,如果我将每个侦听器排队,以便在单独的请求上处理它们,则停止一个侦听器请求的异常不会影响任何其他请求。
  • 最后,您在comment here 中使用的解决方案符合我的建议。最好切换到更适合手头任务的工具,而不是试图强迫错误。而且我并没有说应该处理所有异常,只是说只要您希望执行保持不间断,就应该处理所有异常。这就是语言的工作方式。
  • 好吧,从长远来看,我们的问题是由 cron 任务期间调用的事件引起的,并且各种听众都在听它。但是第一个侦听器因意外异常而失败,然后其他侦听器都没有被调用。我们在日志中看到了这个错误,但认为它的优先级很低,所以我们花时间修复它,没有意识到它正在阻止一些非常重要的听众完成他们的工作。该异常是出乎意料的,避免该问题的唯一方法是将整个侦听器方法包装在一个非常通用的 try/catch 中。这可能发生在任何听众身上。
  • 确实,我有好几份这样的工作。如果需要执行以具有弹性,则解决方案是处理可能的异常。非常非常罕见的方法或函数可以抛出 undocumented 异常。如果一个异常是为了停止执行,你可以让它不被处理。否则,处理它并在那里记录您需要的任何内容。
猜你喜欢
  • 2023-03-14
  • 2016-02-28
  • 1970-01-01
  • 2012-03-01
  • 1970-01-01
  • 2016-01-07
  • 2015-12-19
  • 1970-01-01
  • 2021-12-18
相关资源
最近更新 更多