Nservice автобусных саг реализация
У меня есть проект nservice bus, который я назову соединителем. Мой соединитель получает различные виды сообщений, например ClientChangeMessage, ClientContactChangeMessage. Мой соединитель не реализовал сагу, поэтому у меня есть обработчик для каждого сообщения, поэтому для ClientChangeMessage у меня есть ClientChangeMessageHandler, который срабатывает, когда соединитель получает ClientChangeMessage и ClientContactChangeMessageHandler, когда я получаю ClientContactChangeMessage.
Теперь, глядя на реализацию sagas, я обнаружил, что пишу следующий код (если сообщение о контакте с клиентом предшествует сообщению ClientChange, т.е. клиент не существует в базе данных):
public class ClientContactChangeMessageHandler : ClientMessageHandler,
IHandleMessages<ClientContactChangeMessage>,
IAmStartedByMessages<ClientContactChangeMessage>,
IHandleMessages<ClientChangeMessage>
{
[SetterProperty]
public IClientContactChangeDb ClientContactChangeDb{get;set;}
[SetterProperty]
public IBusRefTranslator BusRefTranslator{get;set;}
static ClientContactChangeMessageHandler()
{
Logger = LogManager.GetLogger(typeof (ClientContactChangeMessageHandler));
}
static ILog Logger;
public void Handle(ClientContactChangeMessage message)
{
//Some handling logic
}
public void Handle(ClientChangeMessage message)
{
throw new NotImplementedException();
}
public override void ConfigureHowToFindSaga()
{
ConfigureMapping<ClientContactChangeMessage>(s => s.Id, m => m.Id);
ConfigureMapping<ClientChangeMessage>(s => s.Id, m => m.Id);
// Notice that we have no mappings for the OrderAuthorizationResponseMessage message. This is not needed since the HR
// endpoint will do a Bus.Reply and NServiceBus will then automatically correlate the reply back to
// the originating saga
}
}
public class ClientMessageHandler : BaseMessageHandler
{
}
public class BaseMessageHandler : Saga<MySagaData>
{
}
public class MySagaData : IContainSagaData
{
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
}
Как видно из примера, теперь я должен также реализовать дескриптор для CLientChangeMessage, теперь я уже определил обработчик для моего ClientChangeMessage, должен ли я обрабатывать его здесь снова, потому что, если в будущем со временем ClientChangeMessage действительно придет я ожидал бы, что это будет поймано и обработано ClientChangeMessageHandler и не этим.
Я хотел бы сохранить сообщение, если и только если я не найду локальную ссылку для Клиента в моей базе данных. Глядя на примеры для саги в Интернете, я не вижу какого-либо конкретного места или условия, где это будет обработано. Я надеюсь, что я буду хранить сообщение внутри метода дескриптора ClientContactChange.
Любая помощь приветствуется,
Спасибо
ОБНОВИТЬ:
Казалось бы, я не совсем понял, как реализовать NService Bus Saga. Ошибка, которую я сделал здесь, в соответствии со мной, заключалась в том, что я считал изменение Контакта клиента единой сущностью, то есть независимым от сообщения Изменения клиента. Поэтому я считаю, что ошибаюсь в реализации Saga только для изменения контактов с клиентами. Вот как я должен был изменить свой код:
public class ClientSaga : Saga<ClientSagaState>,
IAmStartedByMessages<ClientChangeMessage>,
IAmStartedByMessages<ClientContactChangeMessage>,
IHandleTimeout<ClientSagaState>
{
[SetterProperty]
public IClientContactChangeDb ClientContactChangeDb{get;set;}
[SetterProperty]
public IBusRefTranslator BusRefTranslator{get;set;}
public void Handle(ClientContactChangeMessage message)
{
//Some handling logic
//Check if client is not in database then store the state
this.ClientContactChange=message;
//if client is in the data base then
MarkAsComplete();
}
public void Handle(ClientChangeMessage message)
{
//Update or create the client depending on the situation
//check for dependencies
if(this.ClientContactChange !=null)
{
//Handle the contact change
}
}
public override void ConfigureHowToFindSaga()
{
ConfigureMapping<ClientContactChangeMessage>(s => s.ClientRef, m => m.ClientRef);
ConfigureMapping<ClientChangeMessage>(s => s.ClienttnRef, m => m.Id);
// Notice that we have no mappings for the OrderAuthorizationResponseMessage message. This is not needed since the HR
// endpoint will do a Bus.Reply and NServiceBus will then automatically correlate the reply back to
// the originating saga
}
}
public class ClientSagaState: IContainSagaData
{
//i dont need these three fields
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
// the fields which i needed
public Guid ClientRef {gee; set;}
public ClientChangeMessage ClientChange {get;set;}
public ClientContactChange ClientContactChange {get;set;}
}
1 ответ
Поскольку оба обработчика обрабатывают один и тот же тип сообщения, будут вызваны оба. Если хотите, вы можете указать порядок, в котором они будут вызываться, используя ISpecifyMessageHandlerOrdering. Кроме того, вы можете замкнуть цепь на короткое замыкание в зависимости от состояния, которое может решить вторичную проблему.
Если это не сработает, вы можете рассмотреть возможность создания версий сообщения для изящной поддержки обоих сценариев.