MassTransit:如何在Saga状态持久化后立即回复请求
问题:MassTransit Saga状态持久化后立即回复请求
我是MassTransit新手,想咨询:如何在所有活动完成且Saga阶段持久化后立即回复请求?是否可行?
我曾尝试直接使用Respond方法,但控制器有时会获取到null,希望在TransitionTo到GetAdditionalData.Pending状态且该状态持久化后,回复CreateDataResponse。
示例代码
控制器代码
private readonly IRequestClient<CreateDataRequest> client; private readonly TestDbContext db; // dbContext from saga [HttpPost] public async Task<IActionResult> CreateData(CreateData model) { var id = Guid.NewGuid(); var response = await client.GetResponse<CreateDataResponse>(new CreateDataRequest(id, model.UserId)); var state= await db.Data.FirstOrDefaultAsync(s => s.CorrelationId == id); return Ok(state); }
状态机代码
private EventActivityBinder<ApplicationState, CreateDataRequest> CreateDataReceived; Initially( When(CreateDataReceived) .Then(s => { s.Saga.UserId = s.Message.UserId; }) // I tried like this, but sometimes is controler I get null // .Respond(x => new CreateDataResponse(x.Message.CorrelationId)) .Request(GetAdditionalData, c => new GetAdditionalDataRequest(c.Message.CorrelationId)) .TransitionTo(GetAdditionalData.Pending) // here I want to respond CreateDataResponse after CurrentSatge=GetData.Pending persisted )
解决方案
要实现Saga状态持久化后再回复请求,你可以调整状态机的操作顺序,将Respond放在TransitionTo之后。MassTransit的Saga状态机中,活动是按配置顺序执行的,状态转换的持久化会在当前活动批次提交完成后,才会执行后续的Respond操作,这样就能保证回复时状态已经持久化。
修改后的状态机代码
private EventActivityBinder<ApplicationState, CreateDataRequest> CreateDataReceived; Initially( When(CreateDataReceived) .Then(s => { s.Saga.UserId = s.Message.UserId; }) .Request(GetAdditionalData, c => new GetAdditionalDataRequest(c.Message.CorrelationId)) .TransitionTo(GetAdditionalData.Pending) // 状态转换并持久化后回复请求 .Respond(x => new CreateDataResponse(x.Message.CorrelationId)) )
控制器优化建议
你不需要在控制器中直接查询Saga的数据库,因为即使收到响应,数据库事务可能还未完全提交(虽然调整后Respond会在持久化后执行,但直接查询仍有风险)。建议直接从响应中获取必要信息返回:
private readonly IRequestClient<CreateDataRequest> client; [HttpPost] public async Task<IActionResult> CreateData(CreateData model) { var id = Guid.NewGuid(); var response = await client.GetResponse<CreateDataResponse>(new CreateDataRequest(id, model.UserId)); // 直接返回响应中的信息,或构造包含状态的结果 return Ok(new { CorrelationId = response.Message.CorrelationId, CurrentStage = "GetAdditionalData.Pending", UserId = model.UserId }); }
如果确实需要查询Saga状态,确保使用与Saga相同的数据库上下文事务,或者等待事务提交完成后再查询,但优先推荐通过响应传递数据的方式,避免潜在的一致性问题。
内容的提问来源于stack exchange,提问作者Stanislav Panov
相关产品推荐
相关产品推荐

