0

我有一个非常令人沮丧的 NServiceBus 问题,我似乎无法弄清楚。我希望你们能对情况有所了解。

我目前正在使用 NServiceBus.Core v5.0 和 NServiceBus.Host v6.0 并在不显眼模式下运行它。

似乎无论我使用什么配置,我总是会遇到某种错误。我将从产生最少问题的配置开始:

案例 1 - 使用自定义装配扫描:

public void Customize(BusConfiguration configuration)
    {
        var endpointName = typeof(EndpointConfig).Namespace;
        configuration.SetUniqueHostId(endpointName);

        configuration.UseSerialization<JsonSerializer>();
        configuration.UsePersistence<NHibernatePersistence, StorageType.Outbox>();

        configuration.AssembliesToScan(new List<Assembly>
        {
            GetType().Assembly,
            typeof(ICustomCommand).Assembly
        });

        configuration.Conventions()
            .DefiningCommandsAs(type => typeof(ICustomCommand).IsAssignableFrom(type));

        configuration.EnableDurableMessages();
        configuration.EnableInstallers();

        var container = ContainerInitializer.Container;
        configuration.UseContainer<AutofacBuilder>(c => c.ExistingLifetimeScope(container));
    }

我在这里注意到的问题如下:

  1. 当启动 NServiceBus 主机应用程序并且持久性 SQL 数据库尚不存在时,不会抛出异常说找不到数据库(在情况 2 中确实如此)。

  2. 我不断收到以下异常:

NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver 无法从超时存储中获取超时

这最终导致应用程序崩溃,因为当此错误发生太多次时,ServiceBus 认为足够了,就抛出一个致命异常。

  1. 除了上述问题,应用程序运行完美接收和处理消息......直到发生致命异常

现在,这个有点困难:

案例 2 - 使用默认程序集扫描:

public void Customize(BusConfiguration configuration)
    {
        var endpointName = typeof(EndpointConfig).Namespace;
        configuration.SetUniqueHostId(endpointName);

        configuration.UseSerialization<JsonSerializer>();
        configuration.UsePersistence<NHibernatePersistence, StorageType.Outbox>();

        // !! DISABLED !!
        // configuration.AssembliesToScan(new List<Assembly>
        // {
        //    GetType().Assembly,
        //    typeof(ICustomCommand).Assembly
        // });

        configuration.Conventions()
            .DefiningCommandsAs(type => typeof(ICustomCommand).IsAssignableFrom(type));

        configuration.EnableDurableMessages();
        configuration.EnableInstallers();

        var container = ContainerInitializer.Container;
        configuration.UseContainer<AutofacBuilder>(c => c.ExistingLifetimeScope(container));
    }

在这种情况下,会出现以下问题:

当持久化 SQL 数据库尚不存在时:

  1. 启动 NServiceBus 宿主应用程序且 SQL 数据库不存在时,抛出异常 - 预期行为(这是肯定的)

创建持久化 SQL 数据库后:

  1. ServiceControl.Plugin.Nsb5.Heartbeat.Heartbeats|无法将心跳发送到 ServiceControl:NServiceBus.Unicast.Queuing.QueueNotFoundException:无法将消息发送到地址:[Particular.ServiceControl@MYPCNAME]

  2. 引发的异常:System.Messaging.dll 中的“System.Messaging.MessageQueueException”附加信息:外部组件引发了异常。

  3. 2017-09-15 16:25:45.6743|Warn|NServiceBus.Unicast.Messages.MessageMetadataRegistry|消息标头“SharedTemp.Interfaces.ICustomCommand”已映射到“SharedTemp.Interfaces.ICustomCommand”类型,但在消息中找不到该类型注册表 [...]

  4. 抛出异常:NServiceBus.Core.dll 中的“System.Exception”附加信息:找不到“Newtonsoft.Json.Linq.JObject”的元数据。

现在,异常 3 和 4 特别奇怪(不是双关语),因为 NServiceBus 文档指出:

默认情况下,端点 bin 目录中的所有程序集都被扫描以查找实现其接口的类型,以便它可以自动配置它们。

“Newtonsoft.Json”和我的“SharedTemp dll”确实在 BIN 文件夹中,但 NServiceBus 似乎没有找到它们。至于第 1 点:NServiceBus 不会为我创建该队列,但它会创建我需要的所有其他队列。

最后总是请求的 app.config 文件:

    <?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="MasterNodeConfig" type="NServiceBus.Config.MasterNodeConfig, NServiceBus.Core"/>
    <section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core"/>
    <section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core"/>
    <section name="AuditConfig" type="NServiceBus.Config.AuditConfig, NServiceBus.Core"/>
  </configSections>
  <appSettings>
    <add key="NServiceBus/Persistence/NHibernate/dialect" value="NHibernate.Dialect.MsSql2012Dialect"/>
    <add key="NServiceBus/Outbox" value="true"/>
  </appSettings>
  <MessageForwardingInCaseOfFaultConfig ErrorQueue="error"/>
  <UnicastBusConfig>
    <MessageEndpointMappings />
  </UnicastBusConfig>
  <AuditConfig QueueName="audit"/>
  <connectionStrings>
    <add name="NServiceBus/Persistence" connectionString="Server=(LocalDB)\v11.0;Initial Catalog=NServiceBus;Integrated Security=true"/>
  </connectionStrings>
  <system.web>
    <membership defaultProvider="ClientAuthenticationMembershipProvider">
      <providers>
        <add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri=""/>
      </providers>
    </membership>
    <roleManager defaultProvider="ClientRoleProvider" enabled="true">
      <providers>
        <add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400"/>
      </providers>
    </roleManager>
  </system.web>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
  </startup>
  <MasterNodeConfig Node="localhost"/>
</configuration>

有没有人对此有任何想法?

4

1 回答 1

0

经过大量搜索,我终于找到了问题!

首先,我使用了一个内部 NuGet 包,它可以帮助我配置 NServiceBus。该包在其他项目中运行良好,但对我的项目来说不是很好,因为我使用的是 JsonSerialization 而不是默认的 XML 序列化。

该包的第一个问题是它使用“INeedInitialization”接口来配置NServiceBus。然后在我的代码中调用“IConfigureThisEndpoint”来启用 JsonSerialization。这里的问题是,当启动 NServiceBus 主机时,它会找不到 NewtonSoft.Json 库。如果我随后将自定义程序集扫描添加到我自己的配置代码中,它不会触发“INeedInitialization”,从而导致配置不完整/不正确。

我假设它无法加载 NewtonSoft.Json 库,因为扫描是在包的代码/命名空间中触发的?也许@Sean Farmer 可以回答这个问题?

该包的第二个问题是它会将连接字符串添加到 app.config,一个用于“NServiceBus/Persistence”,一个用于“NServiceBus/Persistence/NHibernate/Saga”。我没有使用 Saga,因此不需要连接字符串。最初这不是问题,因为我第一次发现它,但是在重新安装软件包后我完全忘记了它。再次删除它似乎也让 NServiceBus 更快乐。

那么,最终的工作是什么?我删除了包并自己进行了配置,结果如下:

public void Customize(BusConfiguration configuration)
    {
        var endpointName = typeof(EndpointConfig).Namespace;
        configuration.UniquelyIdentifyRunningInstance().UsingCustomIdentifier(endpointName);

        configuration.EnableOutbox();
        configuration.UsePersistence<NHibernatePersistence>();
        configuration.Transactions().DefaultTimeout(TimeSpan.FromMinutes(5.0));

        configuration.UseSerialization<JsonSerializer>();

        configuration.Conventions()
            .DefiningCommandsAs(type => typeof(ICustomCommand).IsAssignableFrom(type));

        configuration.EnableDurableMessages();
        configuration.EnableInstallers();

        var container = ContainerInitializer.Container;
        configuration.UseContainer<AutofacBuilder>(c => c.ExistingLifetimeScope(container));
    }

@Sean:感谢您允许我与您联系。幸运的是没有必要

@Mike:感谢您的输入

于 2017-09-21T10:47:43.977 回答