【问题标题】:Can NServiceBus publish to subscribers in the same AppDomain?NServiceBus 可以发布到同一个 AppDomain 中的订阅者吗?
【发布时间】:2013-09-20 14:11:49
【问题描述】:

我有一个简单的网站。在我的 API 控制器中,我正在捕获命令并将其发送给处理程序。这完美地工作。在处理程序中我做了一些处理,然后发布一个事件。该事件永远不会被发布。我什至无法开始描述我为使其正常工作所做的更改列表,但都无济于事。

关于我的应用程序与任何示例之间的唯一不同之处在于,我的应用程序在同一个程序集中拥有发布者和订阅者。目前,我认为不需要单独的 NServiceBus 进程,尽管我可能会在某个时候这样做。

处理程序

public sealed class PortfoliosHandler : IHandleMessages<CreatePortfolioCommand>, IHandleMessages<PortfolioCreatedEvent>
{
    public void Handle(CreatePortfolioCommand message)
    {
        // Processing logic, this executes just fine

        Bus.Publish(new PortfolioCreatedEvent { Name = portfolio.Name });
    }

    public void Handle(PortfolioCreatedEvent message)
    {
        // This NEVER executes
    }
}

配置

<UnicastBusConfig ForwardReceivedMessagesTo="audit">
    <MessageEndpointMappings>
        <add Assembly="Project.Domain" Namespace="Project.Domain.PM.Commands" Endpoint="messagebus" />
        <add Assembly="Project.Domain" Namespace="Project.Domain.PM.Events" Endpoint="messagebus" />
    </MessageEndpointMappings>
</UnicastBusConfig>

配置代码

NServiceBus.Configure.Transactions.Enable();

var config = NServiceBus.Configure.With();

config = config
    .AutofacBuilder(container)
    .Log4Net(new DebugAppender {Threshold = Level.Warn})
    .UseTransport<Msmq>()
    .PurgeOnStartup(true)
    .UnicastBus()
    .LoadMessageHandlers()
    .RunHandlersUnderIncomingPrincipal(false)
    .InMemorySubscriptionStorage()
    .UseInMemoryTimeoutPersister();

var bus = config
    .CreateBus()
    .Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>()
                            .Install());

不仅事件处理程序永远不会触发,而且队列中也不会出现任何事件消息,日志中也不会出现发布事件的记录。就好像我从来没有寄过一样。以下是调用上述 Publish 方法发出的日志条目:

NServiceBus.Unicast.UnicastBus: 15:52:11,984 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.Transports.Msmq.CorrelationIdMutatorForBackwardsCompatibilityWithV3
NServiceBus.Unicast.UnicastBus: 15:52:11,984 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.Transports.Msmq.CorrelationIdMutatorForBackwardsCompatibilityWithV3
NServiceBus.Unicast.UnicastBus: 15:52:12,240 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.Impersonation.Windows.WindowsIdentityEnricher
NServiceBus.Unicast.UnicastBus: 15:52:12,240 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.Impersonation.Windows.WindowsIdentityEnricher
NServiceBus.Unicast.UnicastBus: 15:52:12,488 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.Unicast.Monitoring.VersionMutator
NServiceBus.Unicast.UnicastBus: 15:52:12,488 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.Unicast.Monitoring.VersionMutator
NServiceBus.Unicast.UnicastBus: 15:52:12,743 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.Unicast.Monitoring.SentTimeMutator
NServiceBus.Unicast.UnicastBus: 15:52:12,743 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.Unicast.Monitoring.SentTimeMutator
NServiceBus.Unicast.UnicastBus: 15:52:12,984 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.Unicast.Monitoring.CausationMutator
NServiceBus.Unicast.UnicastBus: 15:52:12,984 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.Unicast.Monitoring.CausationMutator
NServiceBus.Unicast.UnicastBus: 15:52:13,228 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.Sagas.OriginatingSagaHeaderMutator
NServiceBus.Unicast.UnicastBus: 15:52:13,228 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.Sagas.OriginatingSagaHeaderMutator
NServiceBus.Unicast.UnicastBus: 15:52:13,475 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.Sagas.AutoCorrelateSagaOnReplyMutator
NServiceBus.Unicast.UnicastBus: 15:52:13,475 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.Sagas.AutoCorrelateSagaOnReplyMutator
NServiceBus.Unicast.UnicastBus: 15:52:13,721 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.MessageHeaders.MessageHeaderManager
NServiceBus.Unicast.UnicastBus: 15:52:13,721 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.MessageHeaders.MessageHeaderManager
NServiceBus.Unicast.UnicastBus: 15:52:13,969 DEBUG UnicastBus:0 - Invoking transport message mutator: NServiceBus.Gateway.HeaderManagement.GatewayHeaderManager
NServiceBus.Unicast.UnicastBus: 15:52:13,969 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Invoking transport message mutator: NServiceBus.Gateway.HeaderManagement.GatewayHeaderManager

这些是此后不久出现的日志条目:

NServiceBus.Unicast.UnicastBus: 15:52:58,866 DEBUG UnicastBus:0 - Finished handling message.
NServiceBus.Unicast.UnicastBus: 15:52:58,866 [23] DEBUG NServiceBus.Unicast.UnicastBus [(null)] <(null)> - Finished handling message.
NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver: 15:53:00,900 DEBUG TimeoutPersisterReceiver:0 - Polling for timeouts at 09/20/2013 15:53:00.
NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver: 15:53:00,900 [17] DEBUG NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver [(null)] <(null)> - Polling for timeouts at 09/20/2013 15:53:00.
NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver: 15:53:01,152 DEBUG TimeoutPersisterReceiver:0 - Polling next retrieval is at 09/20/2013 15:54:01.
NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver: 15:53:01,152 [17] DEBUG NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver [(null)] <(null)> - Polling next retrieval is at 09/20/2013 15:54:01.

请帮忙。我已经黔驴技穷了。由于命令、事件和消息之间的分离,我从 MassTransit 移植到 NServiceBus,但经过 4 天的努力,MassTransit 看起来非常好。

我确信我正在做的事情真的很愚蠢,但我是 NServicebus 的菜鸟。我什至买了这本书试图帮助我,但无济于事。我看不出我做错了什么,而且我尝试了很多设置排列,我无法跟踪所有设置。

2013 年 9 月 23 日更新

我有一个建议:

  • 将处理程序分成两部分:PortfolioCreatedHandler 和 CreatePortfolioHandler。
  • 从处理程序中删除密封
  • 创建了我自己的 SubscriptionStorage,包装 InMemorySubscriptionStorage 用于调试目的

我已经使用 IEvent 来标记我的事件,并使用 ICommand 来标记我的命令。命令由 Web 控制器发布,只有处理程序发布事件。

Init 和 GetSubscriberAddressesForMessage 调用了我的 TestSubscriptionStorage 类,而 Subscribe 和 Ubsubscribe 调用了 not,所以看起来问题是事件没有被订阅,这很难与记录以下条目。

以下是提及 PortfolioCreatedEvent 的日志:

NServiceBus.Unicast.Routing.StaticMessageRouter: 09:34:25,886 DEBUG StaticMessageRouter:0 - Routing for message: Project.Domain.PM.Events.PortfolioCreatedEvent set to messagebus@SL-T50009909L
NServiceBus.Unicast.Routing.StaticMessageRouter: 09:34:25,886 [1] DEBUG NServiceBus.Unicast.Routing.StaticMessageRouter [(null)] <(null)> - Routing for message: Project.Domain.PM.Events.PortfolioCreatedEvent set to messagebus@SL-T50009909L
MessageType: Project.Domain.PM.Events.PortfolioCreatedEvent, Recoverable: True, TimeToBeReceived: Not set
MessageType: Project.Domain.PM.Events.PortfolioCreatedEvent, Recoverable: True, TimeToBeReceived: Not set
NServiceBus.Unicast.MessageHandlerRegistry: 09:34:25,906 DEBUG MessageHandlerRegistry:0 - Associated 'Project.Domain.PM.Events.PortfolioCreatedEvent' message with 'Project.PM.Handers.PortfolioCreatedHandler' handler
NServiceBus.Unicast.MessageHandlerRegistry: 09:34:25,906 [1] DEBUG NServiceBus.Unicast.MessageHandlerRegistry [(null)] <(null)> - Associated 'Project.Domain.PM.Events.PortfolioCreatedEvent' message with 'Project.PM.Handers.PortfolioCreatedHandler' handler
NServiceBus.Unicast.MessageHandlerRegistry: 09:34:25,916 DEBUG MessageHandlerRegistry:0 - Associated 'Project.Domain.PM.Commands.CreatePortfolioCommand' message with 'Project.PM.Handers.CreatePortfolioHandler' handler
NServiceBus.Unicast.MessageHandlerRegistry: 09:34:25,916 [1] DEBUG NServiceBus.Unicast.MessageHandlerRegistry [(null)] <(null)> - Associated 'Project.Domain.PM.Commands.CreatePortfolioCommand' message with 'Project.PM.Handers.CreatePortfolioHandler' handler
NServiceBus.Serializers.XML.XmlMessageSerializer: 09:34:26,120 DEBUG XmlMessageSerializer:0 - Initializing type: Project.Domain.PM.Events.PortfolioCreatedEvent, Project.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
NServiceBus.Serializers.XML.XmlMessageSerializer: 09:34:26,120 [1] DEBUG NServiceBus.Serializers.XML.XmlMessageSerializer [(null)] <(null)> - Initializing type: Project.Domain.PM.Events.PortfolioCreatedEvent, Project.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions.MessageDrivenSubscriptionManager: 09:34:35,445 INFO  MessageDrivenSubscriptionManager:0 - Subscribing to Project.Domain.PM.Events.PortfolioCreatedEvent, Project.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null at publisher queue messagebus@SL-T50009909L
NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions.MessageDrivenSubscriptionManager: 09:34:35,445 [18] INFO  NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions.MessageDrivenSubscriptionManager [(null)] <(null)> - Subscribing to Project.Domain.PM.Events.PortfolioCreatedEvent, Project.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null at publisher queue messagebus@SL-T50009909L
NServiceBus.AutomaticSubscriptions.DefaultAutoSubscriptionStrategy: 09:34:35,555 DEBUG DefaultAutoSubscriptionStrategy:0 - Autosubscribed to event Project.Domain.PM.Events.PortfolioCreatedEvent
NServiceBus.AutomaticSubscriptions.DefaultAutoSubscriptionStrategy: 09:34:35,555 [18] DEBUG NServiceBus.AutomaticSubscriptions.DefaultAutoSubscriptionStrategy [(null)] <(null)> - Autosubscribed to event Project.Domain.PM.Events.PortfolioCreatedEvent

【问题讨论】:

  • 如果你这样做Bus.Send...,它会起作用吗?从那以后,您真的是指发布还是发送?
  • Bus.Send 工作 100%。 Bus.Publish 完全没有任何作用。据我了解 Bus.Send 应该用于命令,而 Bus.Publish 应该用于事件。
  • 此时我已经放弃了 NServiceBus。它根本不起作用。我已经从 NServiceBus 分步指南中提取了代码,即使是那个简单的场景也不起作用。

标签: c# nservicebus


【解决方案1】:

好的,感谢您购买这本书!是的,您绝对可以从同一个 AppDomain 订阅事件。以下是关于可能发生的事情的一些想法。

  • 您是否看到表明他们正在订阅该事件的日志条目?如果没有,那么他们就没有订阅。
  • 你没有为你的命令和事件发布代码,所以我不确定你是使用不显眼模式还是直接实现IEvent。 NServiceBus 4 不会自动订阅任何未被识别为事件的内容。
  • 我在您的代码中看到了InMemorySubscriptionStorage。这使得实际查看该存储有点困难。您可以尝试在某处注入ISubscriptionStorage,以便查看调试器中的内容。或者只是切换到默认的 Raven 订阅存储一段时间,以便您可以导航到 http://localhost:8080 的 RavenDB Studio 并查看订阅文档。
  • 我不确定你为什么要密封你的处理程序类。我想不出可能导致的具体问题,但将其作为可能的问题排除可能是个好主意。
  • 尝试将您的处理程序分成不同的类。无论如何,一个类没有理由同时实现这两者 - 容器将为每条消息启动新实例,因此您无法共享状态,因此最好不要给其他开发人员留下他们可以的印象。
  • this issue 也可能与此有关?

当然,有时我会打破记录,但我会caution you not to publish events from a web application in the first place

【讨论】:

  • 看来订阅还可以,将如上更新更多细节。还将尝试您的 ISubscriptionStorage 方法。
  • RavenDB 订阅不起作用,因为它需要完整的写入权限,并且需要付费的 Raven 许可证,而且我们仅处于评估阶段。将尝试 ISubscriptionStorage 的想法。
  • 什么?您的 NServiceBus 许可证可让您充分利用 RavenDB 进行与 NServiceBus 相关的存储,例如订阅。
  • 可能连接到错误的 RavenDB 实例。无论如何,重点是没有意义的。没有任何订阅,尽管日志似乎表明它是。
  • 您认为我还有什么可以尝试的吗?在这个时间点,我正在考虑放弃 NServiceBus 并回到 MassTransit。要么从头开始重做我的解决方案,以使处理程序不在与网站相同的 AppDomain 中。
猜你喜欢
  • 2012-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多