ASP.NET应用程序能处理NServiceBus事件吗?

6
大多数如果不是所有的ASP.NET(或MVC)的NSB示例都有Web应用程序使用Bus.Send发送消息,可能还注册了一个简单的回调,这基本上就是我在我的应用程序中使用它的方式。
我想知道的是,在同一个ASP.NET应用程序中是否有可能和/或有意义地处理消息。
我提出这个问题的主要原因是缓存。该过程可能如下所示:
1. 用户从Web应用程序发起请求。 2. Web应用程序向独立的应用服务器发送消息,并记录本地数据库中的更改。 3. 在以后来自同一用户的页面请求中,Web应用程序知道更改并将其列在“待处理”状态中。 4. 后端会发生很多事情,最终请求被批准或拒绝。发布一个事件引用原始请求。 5. 此时,Web应用程序应该开始显示最新信息。
现在,在一个真正的Web应用程序中,几乎可以确定这个待处理请求会被缓存,很可能长时间被缓存,否则应用程序必须每次用户请求当前信息时查询挂起的更改。
因此,当请求最终在后端完成 - 这可能需要一分钟或一天 - Web应用程序至少需要使此缓存条目失效并进行另一个DB查找。
现在我意识到,这可以通过SqlDependency对象等来管理,但是让我们假设它们不可用 - 可能不是SQL Server后端或当前信息查询转到Web服务等。问题是,Web应用程序如何意识到状态的更改?
如果在ASP.NET应用程序中处理NServiceBus消息是可能的,那么处理程序的上下文是什么?换句话说,IoC容器将不得不注入一堆依赖项,但是它们的范围是什么?所有这些都在HTTP请求的上下文中执行吗?还是每个消息处理程序都需要是静态/单例的?
对于这种类型的问题,有更好/推荐的方法吗?

我不知道如何处理IIS中的事件,但是每当引入异步进程时,您都必须处理最终一致性。Web应用程序是否需要立即更新,还是可以每分钟、15分钟或每小时刷新缓存? - Ryan
@Ryan:我们能逃脱吗?可能可以。从客户的角度来看,我对此感到舒适吗?不是很。我总体上对 EC 没有问题——例如,我意识到如果站点或应用程序池没有运行,则不会处理任何内容,直到它再次启动,而完全没问题——但信息应该在某个用户实际请求它后的几分钟内保持最新,并且数据确实应该缓存更长时间。这种差异通常通过手动或基于依赖项的缓存失效来解决。 - Aaronaught
对,这就是我在同步应用程序中所做的。对于NSB,我每次只需访问数据库,但我只有一个带有少数用户的后台应用程序。 - Ryan
@Ryan:当然,对于小型应用程序,您根本不需要缓存,这将解决问题(尽管我相信在某些情况下,您可能希望从ASP.NET中处理消息)。这是一个面向客户的应用程序,虽然我们不是Stack Overflow规模,但至少可以假设有几百个用户同时在线-缓存绝对很重要。 - Aaronaught
2个回答

3
我自己也曾经想过同样的问题 - 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,发送命令不需要输入队列。这就是为什么我认为Web应用程序发送的单向命令在实践中更为常见。
  4. 这里有很多可以说的单一责任原则。总的来说,我会说,如果你能尽可能地将发送和接收消息的“专业知识”委托给NServiceBus Host,你的整体架构将更加清晰和可管理。通过经验,我发现如果我将我的Web Farm视为单个实体,即剥离所有对个体Web服务器身份的确认,那么我往往会有更少的担忧。每个Web服务器都是总线上的一个端点,这种想法有点打破了这种观念,因为现在“哪个服务器”又以消息队列的形式出现了。

这有助于澄清事情吗?


1

可以创建一个端点(NSB)来订阅已发布的事件并更新缓存。在实际更新完成之前,不应该发布事件,以免出现不同步的情况。Web应用程序将在下一次请求中继续从缓存中获取数据,或者您可以构建某种延迟。


这对我来说听起来有点模糊;当然,事件直到事务实际发生后才会被发布,但在什么时候可以保证它到达 ASP.NET 应用程序中的消息处理程序?你对我的依赖范围问题有什么评论吗?我试图了解一个消息处理程序是否可以承担与绑定到 HTTP 请求(Ninject - InRequestScope)的某些内容的依赖关系。 - Aaronaught
假设它是事务性和持久性的,那么通过传输将得到保证。范围将是每个请求,可以查看AsyncPages示例。这将为页面注册回调并处理消息,这在这种情况下似乎已经足够好了。我只是觉得,在进行下一次读取时更新将会存在,因此您可以执行一些UI操作来帮助它。该网站就是这样工作的,如果您刷新得足够快,则数据不会出现。 - Adam Fyles
这不是完全相同的情况,但我认为这篇文章对于了解NSB/web应用程序背景很有帮助:http://www.make-awesome.com/2010/10/why-not-publish-nservicebus-messages-from-a-web-application/ - Adam Fyles
谢谢 - 我熟悉那个页面,不会从Web应用程序发布事件到NServiceBus,但不幸的是它对作为订阅者处理事件没有太多说明...回调在发起它们的同一请求中执行肯定是有道理的,但似乎就IHandleMessages和订阅而言,我只能进行实验... - Aaronaught
很抱歉我没有更多的信息,但我个人还没有这样做,因为害怕从Web应用程序中窃取资源。我对你的结果很感兴趣。 - Adam Fyles
好的,我不知道在运行处理程序时NServiceBus需要多少资源(尽管我相当确定它会查看输入队列,无论您是否有任何处理程序)。到目前为止,感谢您的建议,我会看看会发生什么并回报。 - Aaronaught

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接