Rebus Saga:将订户发送到发布者时,消息未按正确的顺序到达

时间:2019-08-20 14:25:05

标签: rebus

最近,我们将Rebus版本从1升级到5,然后在遇到Saga处理程序问题之后。现在,我们没有从不同的订户那里以正确的顺序得到响应。

我们有不同的源来对请求进行身份验证,为此,我们有协调器来处理来自不同身份验证源的所有响应,但是现在的问题是:由于以下原因,所有“ SearchStarted”消息都不会首先从所有身份验证源到达协调器我们无法检查有多少个身份验证源开始进行身份验证。

试图以不同的方式发送消息,例如 1.使用SEND方法代替REPLY。 2.在发送响应之前,尝试使用我们的without await关键字。 3.尝试将.Wait()方法与Send / Reply方法一起使用。

AuthenticationCoordinator:

public class AuthenticationSaga : Saga<AuthenticationSagaData>, IAmInitiatedBy<AuthenticationRequest>, IHandleMessages<SearchStarted>, IHandleMessages<SearchCompleted>, IHandleMessages<AuthenticationResponse>
{
    private readonly IBus _bus;

    public IBus Bus
    {
        get { return _bus; }
    }

    public AuthenticationSaga(IBus bus)
    {
        _bus = bus;
    }

    public async Task Handle(AuthenticationRequest message)
    {
        if (!IsNew) return;

        Data.Id = new Guid(MessageContext.Current.Headers[Rebus.Messages.Headers.CorrelationId]);
        Data.ReturnAddress = MessageContext.Current.Headers[Rebus.Messages.Headers.ReturnAddress];
        message.UniqueId = Data.Id.ToString();
        Data.RequestMessage = message;
        Bus.Publish(message);
    }

    public async Task Handle(SearchStarted message)
    {

    }

    public async Task Handle(SearchCompleted message)
    {

    }

    public async Task Handle(AuthenticationResponse message)
    {

    }

    protected override void CorrelateMessages(ICorrelationConfig<AuthenticationSagaData> config)
    {
        config.Correlate<AuthenticationRequest>(m => m.UniqueId, d => d.Id);
        config.Correlate<SearchStarted>(m => m.UniqueId, d => d.Id);
        config.Correlate<AuthenticationResponse>(m => m.UniqueId, d => d.Id);
        config.Correlate<SearchCompleted>(m => m.UniqueId, d => d.Id);
    }
}

AuthenticationLdap:

public class AuthenticationLdapHandler : IHandleMessages
{
    private readonly IBus _bus;

    public IBus bus
    {
        get { return _bus; }
    }

    public AuthenticationLdapHandler(IBus bus)
    {
        _bus = bus;
    }

    public async Task Handle(AuthenticationRequest message)
    {
        await bus.Reply(new SearchStarted { MessageId = MessageContext.Current.Headers[Rebus.Messages.Headers.CorrelationId], UniqueId = message.UniqueId });

        var response = AuthenticateLdap(message); await bus.Reply(response);

        await bus.Reply(new SearchCompleted { MessageId = MessageContext.Current.Headers[Rebus.Messages.Headers.CorrelationId], UniqueId = message.UniqueId });

    }
}

AuthenticationNative:

public class AuthenticationNativeHandler : IHandleMessages
{
    private readonly IBus _bus;

    public IBus bus
    {
        get { return _bus; }
    }

    public AuthenticationNativeHandler(IBus bus)
    {
        _bus = bus;
    }

    public async Task Handle(AuthenticationRequest message)
    {
        await bus.Reply(new SearchStarted { MessageId = MessageContext.Current.Headers[Rebus.Messages.Headers.CorrelationId], UniqueId = message.UniqueId });

        var response = AuthenticateNative(message); await bus.Reply(response);

        await bus.Reply(new SearchCompleted { MessageId = MessageContext.Current.Headers[Rebus.Messages.Headers.CorrelationId], UniqueId = message.UniqueId });

    }
}

我们期望AuthenticationCoordinator中的响应如下所示:

    来自Ldap的
  1. SearchStarted消息

  2. 来自本地的
  3. SearchStarted消息

  4. 来自Ldap的AuthenticationResponse消息
  5. 来自Ldap的SearchCompleted消息
  6. 来自本机的AuthenticationResponse消息
  7. 来自本机的SearchCompleted消息

但是现在我们按以下顺序获得响应:

  1. 来自Ldap的SearchStarted消息
  2. 来自Ldap的AuthenticationResponse消息
  3. 来自Ldap的SearchCompleted消息
  4. 来自本机的SearchStarted消息
  5. 来自本机的AuthenticationResponse消息
  6. 来自本机的SearchCompleted消息

我们可以设置消息优先级吗?我们如何在Rebus 5中获得超出预期的响应。

1 个答案:

答案 0 :(得分:1)

您所看到的很可能是由于Rebus确保在处理程序执行完之后发送所有传出消息的结果。

它通过在其事务上下文中登记所有总线操作来做到这一点,只有在处理程序代码完成后,总线事务才会提交。

这意味着类似的代码

public async Task Handle(string message)
{
    await bus.Reply("this is message 1");

    await Task.Delay(TimeSpan.FromSeconds(1));

    await bus.Reply("this is message 2");

    await Task.Delay(TimeSpan.FromSeconds(1));

    await bus.Reply("this is message 3");
}

当提交Rebus事务上下文时,将导致同时发送消息1、2和3,这意味着收件人将以随机顺序接收它们。

如果要立即从处理程序发送消息,则可以像下面这样“拆除”交易上下文:

var transactionContext = AmbientTransactionContext.Current;
AmbientTransactionContext.SetCurrent(null);
try
{
    // current transaction will never know....
    await bus.Send(whee);
}
finally
{
    AmbientTransactionContext.SetCurrent(transactionContext);
}

我建议您将其封装在IDisposable的实现中,以实现如下用法:

using(new RebusTransactionContextDismantler())
{
    // current transaction will never know....
    await bus.Publish(whee);
}