Невозможно иметь две саги, которые обрабатывают один и тот же тип сообщения.

У меня есть две разные саги (я имею в виду типы саг), которые обрабатывают одно и то же сообщение.

     public class AttachMessageToBugSaga : TpSaga<AttachMessageToBugSagaData>, IAmStartedByMessages<MessageIsNotAttached>, IHandleMessages<MessageAttachedToGeneralMessage>
    {
        public override void ConfigureHowToFindSaga()
        {
            ConfigureMapping<MessageAttachedToGeneralMessage>(
             saga => saga.Id,
             message => message.SagaId
             );
        }
        public void Handle(MessageIsNotAttachedToBug message)
        {
            Send(new AttachMessageToGeneralCommand { MessageId = 66, GeneralId = 13 });
        }

        public void Handle(MessageAttachedToGeneralMessage message)
        {
            //do some stuf fhere
        }
    }

    public class AttachMessageToBugSagaData : IContainSagaData
    {
        public Guid Id { get; set; }
        public string Originator { get; set; }
        public string OriginalMessageId { get; set; }
    }

    public class AttachMessageToRequestSaga : TpSaga<AttachMessageToRequestSagaData>, IAmStartedByMessages<MessageIsNotAttachedToRequest>, IHandleMessages<MessageAttachedToGeneralMessage>
    {
        public override void ConfigureHowToFindSaga()
        {
            ConfigureMapping<MessageAttachedToGeneralMessage>(
             saga => saga.Id,
             message => message.SagaId
             );
        }

        public void Handle(MessageIsNotAttachedMessageToRequest message)
        {
            //do some stuff here
        }

        public void Handle(MessageAttachedToGeneralMessage message)
        {
            //do some stuff here
        }
    }

    public class AttachMessageToRequestSagaData : IContainSagaData
    {
        public Guid Id { get; set; }
        public string Originator { get; set; }
        public string OriginalMessageId { get; set; }
    }

Когда я запускаю образец, я получаю исключение:

System.InvalidCastException: невозможно преобразовать объект типа «MyCustomPlugin.AttachMessageToGeneralSagaData» в тип «MyCustomPlugin.AttachMessageToRequestSagaData».

Я понимаю, почему это происходит, но мне все еще нужен обходной путь. Я попытался реализовать свой собственный класс IFindSagas:

public class SagaFinder : IFindSagas<AttachMessageToGeneralSagaData>.Using<MessageAttachedToGeneralMessage>,
IFindSagas<AttachMessageToRequestSagaData>.Using<MessageAttachedToGeneralMessage>,
IFindSagas<AttachMessageToRequestSagaData>.Using<MessageIsNotAttachedToRequest>,
IFindSagas<AttachMessageToRequestSagaData>.Using<MessageIsNotAttachedToBug>
{
    AttachMessageToGeneralSagaData IFindSagas<AttachMessageToGeneralSagaData>.Using<MessageAttachedToGeneralMessage>.FindBy(MessageAttachedToGeneralMessage message)
    {
        return ObjectFactory.GetInstance<AttachMessageToGeneralSagaData>();
    }

    AttachMessageToRequestSagaData IFindSagas<AttachMessageToRequestSagaData>.Using<MessageAttachedToGeneralMessage>.FindBy(MessageAttachedToGeneralMessage message)
    {
        return ObjectFactory.GetInstance<AttachMessageToRequestSagaData>();
    }

    public AttachMessageToRequestSagaData FindBy(MessageIsNotAttachedToRequest message)
    {
        return new AttachMessageToRequestSagaData();
    }

    public AttachMessageToRequestSagaData FindBy(MessageIsNotAttachedToBug message)
    {
        return new AttachMessageToRequestSagaData();
    }
}

Но я не попадаю в свои поисковики для «MessageAttachedToGeneralMessage». Скажите, пожалуйста, есть ли другой обходной путь или как заставить этот пример работать.


person struhtanov    schedule 20.12.2010    source источник


Ответы (2)


Я не уверен, что наличие более одной саги в пределах одной границы процесса работает очень хорошо - по крайней мере, у меня тоже были проблемы с этим. В любом случае, вероятно, лучше (в целом) разделить саги на два разных процесса, потому что в противном случае это приведет к большому количеству блокировок и потенциально взаимоблокировок в вашем хранилище саги.

Ваше сообщение, которое обрабатывается 2 сагами, отправлено или опубликовано? Если он будет опубликован (или его можно будет сделать), будет легко разделить саги на две отдельные сборки. Просто не забудьте вручную вызвать Bus.Subscribe() для типа сообщения в каждой саге, поскольку саги не подписываются автоматически на сообщения, перечисленные в app.config.

Если ваше сообщение отправлено, и вы ничего не можете сделать, чтобы изменить его, создайте центральный обработчик для вашего существующего типа сообщения, который либо публикует второй тип сообщения для отправки в обе саги, либо отправляет два отдельных сообщения в каждую сагу.

person David Boike    schedule 20.12.2010
comment
Спасибо за ваш ответ Дэвид. Мне непонятно, почему Саги лучше разделить на разные процессы. У меня есть много саг, работающих в одном процессе NServiceBusHost.exe. И мне нужно их много, чтобы разделить мой поток на небольшие логические части. Так что у меня есть что-то вроде конечного автомата, где каждая сага помогает мне переключиться в новое состояние. Но я понимаю вашу мысль. Он должен работать - person struhtanov; 21.12.2010

Наконец (после изучения исходного кода) я нашел решение. Кажется, единственный способ — реализовать свою собственную SagaPersister, где я могу делать все, что захочу.

Реализация InMemorySagaPersister по умолчанию в NserviceBus имеет следующий код:

    T ISagaPersister.Get<T>(Guid sagaId)
    {
        ISagaEntity result;
        data.TryGetValue(sagaId, out result);

        return (T)result;
    }

И исключение возникает при литье.

person struhtanov    schedule 21.12.2010