【问题标题】:Can an ASP.NET application handle NServiceBus events?ASP.NET 应用程序可以处理 NServiceBus 事件吗?
【发布时间】:2012-01-16 20:58:15
【问题描述】:

大多数(如果不是全部)ASP.NET(或 MVC)的 NSB 示例都有 Web 应用程序使用 Bus.Send 发送消息并可能注册一个简单的回调,这基本上是我在应用程序中使用它的方式.

我想知道的是,在同一个 ASP.NET 应用程序中处理消息是否可能和/或有意义。

我问的主要原因是缓存。这个过程可能是这样的:

  1. 用户从网络应用发起请求。
  2. Web 应用向独立应用服务器发送消息,并将更改记录在本地数据库中。
  3. 对于来自同一用户的未来页面请求,Web 应用程序会知道更改并将其列为“待处理”状态。
  4. 后端发生了一堆事情,最终请求被批准或拒绝。引用原始请求发布事件。
  5. 此时,网络应用应该开始显示最新信息。

现在,在真正的 Web 应用程序中,几乎可以肯定的是,这个待处理的请求将被缓存,很可能会被缓存很长时间,因为否则应用程序必须查询数据库以获取待处理的更改 每次用户询问当前信息。

因此,当请求最终在后端完成时(可能需要一分钟或一天),Web 应用程序至少需要使此缓存条目无效并执行另一次数据库查找。

现在我意识到这可以通过 SqlDependency 对象等进行管理,但让我们假设它们不可用 - 也许它不是 SQL Server 后端,或者可能当前信息查询转到网络服务,随便。问题是,Web 应用程序如何知道状态的变化?

如果 可以在 ASP.NET 应用程序中处理 NServiceBus 消息,那么处理程序的上下文是什么?换句话说,IoC 容器将不得不注入一堆依赖项,但它们的范围是什么?这一切都在 HTTP 请求的上下文中执行吗?还是消息处理程序的所有内容都需要是静态/单例的?

对于此类问题是否有更好/推荐的方法?

【问题讨论】:

  • 我不知道如何在 IIS 中处理事件,但无论何时引入异步进程,都必须处理最终一致性。 Web 应用程序是否需要立即更新,或者您可以每分钟、15 分钟、每小时刷新一次缓存吗?
  • @Ryan:我们能侥幸逃脱吗?大概。我对客户 POV 感到满意吗?并不真地。总的来说,我对 EC 没意见 - 例如,我意识到如果站点或应用程序池没有运行,直到它再次启动,并且 that 完全没问题,否则什么都不会被处理 - 但是信息应该在某些用户实际请求它的几分钟内是最新的,并且数据确实应该被缓存更长的时间。这种差异通常通过手动或基于依赖的缓存失效来解决。
  • 对,这就是我在同步应用程序中所做的。对于 NSB,我每次都访问数据库,但我只有一个有几个用户的后台应用程序。
  • @Ryan:当然,对于小型应用程序,您根本不需要缓存,这将解决问题(尽管我确信您可能需要其他场景处理来自 ASP.NET 的消息)。这是一个面向客户的应用程序,虽然我们不是 Stack Overflow 规模,但假设一次至少有几百个用户在线 - 缓存绝对重要。

标签: asp.net asp.net-mvc nservicebus publish-subscribe


【解决方案1】:

我自己也想知道同样的事情 - 对于 Web 应用程序与 NServiceBus 基础架构的适当耦合级别是多少?在我的领域中,我有一个类似的问题需要解决,涉及使用 SignalR 代替缓存。和你一样,我没有找到很多关于这个特定模式的文档。但是,我认为可以通过遵循它的一些含义进行推理,然后确定它在您的环境中是否有意义。

简而言之,我认为让 Web 应用程序订阅 NServiceBus 事件是完全可能的。我不认为会有任何技术障碍,尽管我不得不承认我没有真正尝试过——如果你有时间,一定要试一试。我只是有一种强烈的感觉,如果一个人开始需要这样做,那么可能会有更好的整体设计等待被发现。这就是我认为是这样的原因:

  1. 要问的一个相关问题与您的缓存实现有关。如果它是分布式或集中式模型(想想 SQL、MongoDB、Memcached 等),那么 @Adam Fyles 建议的方法听起来是个好主意。您不会需要通知每个 Web 应用程序 - 更新缓存可以通过单个 NServiceBus 端点来完成,该端点不是您的 Web 应用程序的一部分。换句话说,您的 Web 应用程序的每个实例和“缓存更新”端点都将访问相同的共享缓存。但是,如果您的缓存在进程中,例如 Microsoft 的 Web 缓存,那么您当然会遇到一个更棘手的问题需要解决,除非您可以按照建议依赖最终一致性。
  2. 如果您的 Web 应用程序订阅了特定的 NServiceBus 事件,那么您有必要为您的 Web 应用程序的每个实例提供一个唯一的输入队列。由于最佳实践是考虑使用负载均衡器扩展您的 Web 应用程序,这意味着您最终可能会得到 N 个队列和至少 N 个订阅,这比固定数量的订阅更令人担忧。再说一次,不是技术障碍,只是让我大吃一惊。
  3. 链接的 David Boike 文章提出了一个有趣的观点,即应用程序池以及它们的生命周期如何不确定。此外,如果您在服务器上为同一个应用程序同时运行多个应用程序池(一种常见情况),它们都将尝试从同一个消息队列中读取,并且没有好的方法来确定哪个将实际处理消息.更多时候,这很重要。相反,根据this post by Udi Dahan,发送命令不需要输入队列。这就是为什么我认为网络应用发送的单向命令在实践中更为常见。
  4. 这里有很多关于单一职责原则的内容。总的来说,我会说,如果您可以将发送和接收消息的“专业知识”尽可能委派给 NServiceBus 主机,那么您的整体架构将更加简洁和易于管理。通过经验,我发现如果我将我的网络农场视为一个单一的实体,即去掉对单个网络服务器身份的所有确认,我往往不必担心。让每个 Web 服务器成为总线上的一个端点就打破了这个概念,因为现在“哪个服务器”又以消息队列的形式出现了。

这有助于澄清事情吗?

【讨论】:

    【解决方案2】:

    可以创建一个端点(NSB)来订阅已发布的事件并更新缓存。在进行实际更新之前不应发布该事件,这样您就不会失去同步。 Web 应用会在下一个请求时继续从缓存中提取数据,或者您可以构建某种延迟。

    【讨论】:

    • 这听起来有点模糊;当然,在事务实际发生之前不会发布事件,但是在什么时候可以保证到达 ASP.NET 应用程序中的消息处理程序?你对我关于依赖范围的问题有什么评论吗?我试图了解消息处理程序是否可以依赖绑定到 HTTP 请求的内容(Ninject - InRequestScope)。
    • 假设它是事务性的和持久的,它将通过传输得到保证。范围将是每个请求,请查看 AsyncPages 示例。这为页面注册了一个回调并正在处理消息,这听起来在这种情况下可能已经足够好了。在我看来,到下一次阅读时,更新就会在那里,所以你可以做一些 UI 的事情来帮助它。这个网站就是这样工作的,如果你刷新得足够快,数据就不存在了。
    • 这不是完全相同的情况,但我认为对于 NSB/网络应用程序的一些背景来说,这是一本不错的读物:make-awesome.com/2010/10/…
    • 谢谢 - 我熟悉那个页面,不会从网络应用程序向 NServiceBus 发布事件,但不幸的是,作为订阅者处理事件并没有太多可说的......它肯定会让感觉回调将在发起它们的同一请求中执行,但似乎就IHandleMessages 和订阅而言,我只需要进行实验......
    • 很抱歉我没有更多信息,但我没有亲自这样做,因为害怕从网络应用程序中窃取资源。我会对你的结果感兴趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    相关资源
    最近更新 更多