Не удается получить NServiceBus, чтобы не генерировать исключения (MessageQueueException, SqlException, TimeoutPersisterReceiver)
У меня очень разочаровывающая проблема 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));
}
Проблемы, которые я заметил здесь, следующие:
При запуске хост-приложения NServiceBus и постоянной базы данных SQL еще не существует, не выдается исключение о том, что база данных не может быть найдена (это происходит в случае 2).
Я продолжаю получать следующее исключение:
NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver Не удалось извлечь тайм-ауты из хранилища тайм-аутов
В конечном итоге это приводит к сбою приложения, потому что когда эта ошибка возникает слишком много раз, 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 не существует, исключение - throw - Ожидаемое поведение (это положительно)
После создания персистентной базы данных SQL:
ServiceControl.Plugin.Nsb5.Heartbeat.Heartbeats | Невозможно отправить пульс в ServiceControl: NServiceBus.Unicast.Queuing.QueueNotFoundException: Не удалось отправить сообщение на адрес: [Particular.ServiceControl@MYPCNAME]
Возникло исключение: System.Messaging.MessageQueueException в System.Messaging.dll Дополнительная информация: Внешний компонент выдал исключение.
2017-09-15 16: 25: 45.6743 | Warn | NServiceBus.Unicast.Messages.Messages.MessageMetadataRegistry | Заголовок сообщения "SharedTemp.Interfaces.ICustomCommand" сопоставлен с типом "SharedTemp.Interfaces.ICustomCommand", но этот тип не найден в сообщении. реестр [...]
Возникло исключение: "System.Exception" в NServiceBus.Core.dll Дополнительная информация: Не удалось найти метаданные для "Newtonsoft.Json.Linq.JObject".
Теперь исключения 3 и 4 особенно странны (без каламбура), так как документация NServiceBus гласит:
По умолчанию все сборки в каталоге bin конечной точки сканируются, чтобы найти типы, реализующие его интерфейсы, чтобы он мог настроить их автоматически.
И "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>
У кого-нибудь есть идеи по этому поводу?
1 ответ
После долгих поисков я наконец нашел проблему!
Прежде всего, я использовал собственный пакет 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: Спасибо, что позволили мне связаться с вами. К счастью, это было не нужно
@ Майк: Спасибо за вклад