You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

切换到MassTransit.Marten后,Saga完成时未自动删除的问题排查

Saga状态机切换到Marten/Postgres后,Final状态实例未被自动删除

问题背景

首次实现Saga,此前用InMemory仓库测试一切正常,切换到Marten/Postgres后发现:触发超时事件将状态设为Final后,Saga实例并未被自动删除。由于和第三方系统交互无法获取其Guid关联ID,因此使用了对方的标识信息作为关联依据。

代码配置

Saga实例类

public class GroupSaga : SagaStateMachineInstance
{
    public string Partition { get; set; }

    public Guid CorrelationId { get; set; }

    public string CurrentState { get; set; }
}

超时事件类

class CommsTimeoutEvent : ICommsTimeout
{
    readonly GroupSaga _instance;

    public CommsTimeoutEvent(GroupSaga instance)
    {
        _instance = instance;
    }

    public Guid SagaGuid => _instance.CorrelationId;
}

状态机核心配置

Event(() => MyEventReceived,
            x => x.CorrelateBy(rsp => rsp.Partition, context => context.Message.Partition)
                .SelectId(_ => NewId.NextGuid()));

Schedule(() => CommsTimedOut, x => x.ExpirationId, x =>
        {
            x.Delay = TimeSpan.FromSeconds(10);
            x.Received = e => e.CorrelateById(context => context.Message.SagaGuid);
        });

Initially(
            When(MyEventReceived)
                .Then(context =>
                {
                    context.Saga.Partition = context.Message.Partition;
                })
                .Activity(x => x.OfInstanceType<CustomActivity>())
                .Schedule(CommsTimedOut, context => new CommsTimeoutEvent(context.Saga))
                .TransitionTo(WaitingForResponse));

// 省略其他状态流转配置
DuringAny(
            When(CommsTimedOut.Received)
                .Finalize());

SetCompletedWhenFinalized();

Marten初始化代码

config.AddSagaStateMachine<GroupStateMachine, GroupSaga>()
                .MartenRepository(dbConnectionString);

问题现象

触发超时后,数据库表中Saga的CurrentState字段显示为Final,但实例从未被自动删除。再次触发启动事件MyEventReceived时会报错,因为初始事件无法在Final状态下处理。


解决方法

问题根源在于Marten Saga仓库的默认行为:InMemory仓库会自动删除Final状态实例,但Marten仓库默认不会主动清理,需要手动配置清理策略:

  1. 启用自动清理配置
    在Marten仓库初始化时,添加CleanupRemovedSagas选项指定清理间隔:

    config.AddSagaStateMachine<GroupStateMachine, GroupSaga>()
            .MartenRepository(dbConnectionString, repoConfig =>
            {
                // 配置每小时清理一次Final状态的Saga实例
                repoConfig.CleanupRemovedSagas(TimeSpan.FromHours(1));
            });
    
  2. 确认状态机标记逻辑
    确保SetCompletedWhenFinalized()已正确添加到状态机配置中,这个方法会将Final状态的Saga标记为待删除状态,供后续清理任务处理。

  3. 手动触发清理(可选)
    如果需要立即清理已标记的实例,可以在应用启动或定时任务中调用Marten的清理方法:

    using var session = documentStore.LightweightSession();
    await session.DeleteExpiredSagasAsync();
    session.SaveChanges();
    

补充说明

Marten不会实时删除Final状态的Saga,而是通过后台定时任务(默认每分钟检查一次,实际清理间隔由CleanupRemovedSagas参数决定)批量清理标记为已完成的实例。如果需要更及时的清理,可以缩短间隔,但需注意不要过于频繁导致数据库性能损耗。

内容的提问来源于stack exchange,提问作者Pete Roberts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 17:10:30