无法让 NServiceBus 不抛出异常(MessageQueueException、SqlException、TimeoutPersisterReceiver)
Cannot get NServiceBus to not throw exceptions (MessageQueueException, SqlException, TimeoutPersisterReceiver)
我有一个非常令人沮丧的 NServiceBus 问题,我似乎无法弄清楚。我希望你们能对情况有所了解。
我目前正在使用 NServiceBus.Core v5.0 和 NServiceBus.Host v6.0 以及 运行 Unobtrusive Mode。
似乎无论我使用什么配置,我总是会遇到某种错误。我将从产生最少问题的配置开始:
案例 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));
}
我在这里注意到的问题如下:
当启动NServiceBus宿主应用程序并且持久化SQL数据库还不存在时,没有抛出异常说找不到数据库(在情况2中确实如此)。
我不断收到以下异常:
NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver Failed to fetch timeouts from the timeout storage
这最终会导致应用程序崩溃,因为当此错误发生次数过多时,ServiceBus 会认为已经足够了,只会抛出致命异常。
- 除上述问题外,应用程序运行完美地接收和处理消息...直到发生致命异常
现在,这个有点难:
案例 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数据库还不存在时:
- 启动 NServiceBus 主机应用程序且 SQL 数据库不存在时,抛出异常 - 预期行为(这是肯定的)
创建持久性SQL数据库后:
ServiceControl.Plugin.Nsb5.Heartbeat.Heartbeats|Unable to send heartbeat to ServiceControl:
NServiceBus.Unicast.Queuing.QueueNotFoundException: Failed to send message to address: [Particular.ServiceControl@MYPCNAME]
Exception thrown: 'System.Messaging.MessageQueueException' in System.Messaging.dll
Additional information: External component has thrown an exception.
2017-09-15 16:25:45.6743|Warn|NServiceBus.Unicast.Messages.MessageMetadataRegistry|Message header 'SharedTemp.Interfaces.ICustomCommand'
was mapped to type 'SharedTemp.Interfaces.ICustomCommand' but that type was not found in the message registry [...]
Exception thrown: 'System.Exception' in NServiceBus.Core.dll
Additional information: Could not find metadata for 'Newtonsoft.Json.Linq.JObject'.
现在,异常 3 和 4 特别(没有双关语意)很奇怪,因为 NServiceBus 文档指出:
By default all assemblies in the endpoint bin directory are scanned to find types implementing its interfaces so that it can configure them automatically.
而我的"Newtonsoft.Json"和我的"SharedTemp dll's"确实在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>
有没有人对此有任何想法?
找了很久终于找到问题了!
首先,我使用了一个内部 NuGet 包,它可以帮助我配置 NServiceBus。该包在其他项目上运行良好,但对我的项目来说不太好,因为我使用的是 JsonSerialization 而不是默认的 XML 序列化。
该包的第一个问题是它使用了 "INeedInitialization" 接口来配置 NServiceBus。在我的代码中,我会调用 "IConfigureThisEndpoint" 来启用 JsonSerialization。这里的问题是,当启动 NServiceBus 主机时,它会找不到 NewtonSoft.Json 库。如果我随后将自定义程序集扫描添加到我自己的配置代码中,它不会触发 "INeedInitialization",导致 incomplete/incorrect 配置。
我假设它无法加载 NewtonSoft.Json 库,因为扫描是在包的 code/namespace 中触发的?也许@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:感谢您的投入
我有一个非常令人沮丧的 NServiceBus 问题,我似乎无法弄清楚。我希望你们能对情况有所了解。
我目前正在使用 NServiceBus.Core v5.0 和 NServiceBus.Host v6.0 以及 运行 Unobtrusive Mode。
似乎无论我使用什么配置,我总是会遇到某种错误。我将从产生最少问题的配置开始:
案例 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));
}
我在这里注意到的问题如下:
当启动NServiceBus宿主应用程序并且持久化SQL数据库还不存在时,没有抛出异常说找不到数据库(在情况2中确实如此)。
我不断收到以下异常:
NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver Failed to fetch timeouts from the timeout storage
这最终会导致应用程序崩溃,因为当此错误发生次数过多时,ServiceBus 会认为已经足够了,只会抛出致命异常。
- 除上述问题外,应用程序运行完美地接收和处理消息...直到发生致命异常
现在,这个有点难:
案例 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数据库还不存在时:
- 启动 NServiceBus 主机应用程序且 SQL 数据库不存在时,抛出异常 - 预期行为(这是肯定的)
创建持久性SQL数据库后:
ServiceControl.Plugin.Nsb5.Heartbeat.Heartbeats|Unable to send heartbeat to ServiceControl: NServiceBus.Unicast.Queuing.QueueNotFoundException: Failed to send message to address: [Particular.ServiceControl@MYPCNAME]
Exception thrown: 'System.Messaging.MessageQueueException' in System.Messaging.dll Additional information: External component has thrown an exception.
2017-09-15 16:25:45.6743|Warn|NServiceBus.Unicast.Messages.MessageMetadataRegistry|Message header 'SharedTemp.Interfaces.ICustomCommand' was mapped to type 'SharedTemp.Interfaces.ICustomCommand' but that type was not found in the message registry [...]
Exception thrown: 'System.Exception' in NServiceBus.Core.dll Additional information: Could not find metadata for 'Newtonsoft.Json.Linq.JObject'.
现在,异常 3 和 4 特别(没有双关语意)很奇怪,因为 NServiceBus 文档指出:
By default all assemblies in the endpoint bin directory are scanned to find types implementing its interfaces so that it can configure them automatically.
而我的"Newtonsoft.Json"和我的"SharedTemp dll's"确实在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>
有没有人对此有任何想法?
找了很久终于找到问题了!
首先,我使用了一个内部 NuGet 包,它可以帮助我配置 NServiceBus。该包在其他项目上运行良好,但对我的项目来说不太好,因为我使用的是 JsonSerialization 而不是默认的 XML 序列化。
该包的第一个问题是它使用了 "INeedInitialization" 接口来配置 NServiceBus。在我的代码中,我会调用 "IConfigureThisEndpoint" 来启用 JsonSerialization。这里的问题是,当启动 NServiceBus 主机时,它会找不到 NewtonSoft.Json 库。如果我随后将自定义程序集扫描添加到我自己的配置代码中,它不会触发 "INeedInitialization",导致 incomplete/incorrect 配置。
我假设它无法加载 NewtonSoft.Json 库,因为扫描是在包的 code/namespace 中触发的?也许@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:感谢您的投入