【问题标题】:How to handle state transition inside a rebus saga?如何处理 rebus saga 中的状态转换?
【发布时间】:2015-09-17 18:54:24
【问题描述】:

假设我有一个 saga 数据,其中包含具有以下值之一的状态:

JustWaiting, AwatingPrepareDrink, WaitingForPayment

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

ie.: 仅在状态为 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;
}

但是,这会导致 saga 修订增加,而另一个处理程序正在做一些工作。当另一个处理程序完成时,会发生并发异常,因为同时修订版本有所增加。

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

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

感谢您的帮助!

【问题讨论】:

  • 好问题!我认为如果有可能以某种方式将传奇数据标记为“未更新”,则可以解决 - 例如类似于 MarkAsComplete() 如何以秘密方式标记 saga 数据,最终将其删除,也许像 MarkAsUnchanged() 这样的东西可以满足您的需求......想法?
  • 那太棒了!我想必须明智地使用它,就像 MarkAsComplete() 一样。

标签: rebus


【解决方案1】:

我认为这是一个好主意,所以我将它添加到了 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 数据实例。

【讨论】:

  • 不要误会我的意思,它解决了我的问题,我对此表示感谢,但我现在如何跟踪它已被推迟 10 次,并且我想在 x 数量后停止推迟次?有什么建议吗?
  • 一种方法是在延迟消息中添加一个特殊的标头,您可以在其中记录您尝试处理它的次数
  • 据我了解,当另一个长进程处理程序正在执行时,一个 saga 处理程序无法处理:它会导致并发异常。你不认为这是一个有效的场景吗?
  • 由于 saga 依赖于更新一条数据,并且整个理念都是围绕着保证作为开发人员的您可以将 saga 视为只有一条消息被处理在任何给定时间点的每个 saga 实例,我建议您让另一个消息处理程序执行任何长时间运行的消息处理逻辑,并让 saga 使用请求/回复来进行协调
  • 所以MakeTheDrink 将是一条消息,它会发送给另一个处理程序(例如,作为MakeTheDrinkRequest,它会回复(例如使用MakeTheDrinkReply),然后该处理程序可能需要很长时间正如它想要的那样
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-16
  • 1970-01-01
  • 2017-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多