如何处理 rebus saga 中的状态转换?

How to handle state transition inside a rebus saga?

假设我有一个包含具有以下值之一的状态的传奇数据:

JustWaiting, AwatingPrepareDrink, WaitingForPayment

我也有不同的消息要处理,但只想在状态具有特定值时处理它们。

即:仅当状态为 AwaitingPrepareDrink 时才处理 PrepareDrinkMessage

为了实现这一目标,我目前正在做类似的事情:

public async Task Handle(PrepareDrinkMessage message)
{
    if(Data.CurrentState != BaristaSagaData.State.AwatingPrepareDrink)
    {
        return;
    }

    //do some stuff...


    //state transition
    Data.CurrentState = BaristaSagaData.State.WaitingForPayment;
}

我在使用这种方法时遇到的问题是,传入的消息很可能很快就会收到(工作人员目前可能正在另一个处理程序中工作,该处理程序将转换为正确的状态)。

我试着替换这个:

if(Data.CurrentState != BaristaSagaData.State.AwatingPrepareDrink)
{
    return;
}

有了这个:

if(Data.CurrentState != BaristaSagaData.State.AwatingPrepareDrink)
{
    //too soon, try again in 10 seconds
    await _bus.defer(TimeSpan.FromSeconds(10), message);
    return;
}

但是,这会导致传奇修订增加,而另一个处理程序正在做一些工作。当另一个处理程序完成时,发生并发异常,因为修订已在此期间增加。

有没有其他方法可以防止根据状态处理消息?

有什么方法可以在不影响修订的情况下推迟消息吗?

感谢您的帮助!

我认为这是个好主意,所以我将它添加到 0.98.12,几分钟后 NuGet.org 就可以使用了。

现在您可以更改

if (Data.CurrentState != BaristaSagaData.State.AwatingPrepareDrink)
{
    //too soon, try again in 10 seconds
    await _bus.Defer(TimeSpan.FromSeconds(10), message);
    return;
}

进入

if (Data.CurrentState != BaristaSagaData.State.AwatingPrepareDrink)
{
    //too soon, try again in 10 seconds
    await _bus.Defer(TimeSpan.FromSeconds(10), message);
    MarkAsUnchanged();
    return;
}

让我知道它是否适合你:)

这将导致加载和更新 saga 数据的管道步骤跳过更新此特定 saga 数据实例。