部署到测试服务器时出现 request/response 超时的 MassTransit saga

MassTransit saga with request/response timeouts when deployed to test server

我有一个完整的 MassTransit 传奇,它运行一些命令,然后执行 request/response 调用来查询数据库,然后最终 return 对调用控制器的响应。

在本地,这一切现在 99% 的时间都有效(感谢我在这里收到的大量支持)。然而,当部署到我的 Azure VM 时,它有 RabbitMQ 的本地副本和 2 ASP.NET 核心服务 运行,对 saga 的第一次调用会立即通过,但所有后续调用都会超时。

我觉得这可能与我正在使用 InMemorySagaRepository 这一事实有关(理论上它应该适合我的用例)。

saga 最初配置如下:

InstanceState(s => s.CurrentState);

Event(() => RequestLinkEvent, x => x.CorrelateById(context => context.Message.LinkId));
Event(() => LinkCreatedEvent, x => x.CorrelateById(context => context.Message.LinkId));
Event(() => CreateLinkGroupFailedEvent, x => x.CorrelateById(context => context.Message.LinkId));
Event(() => CreateLinkFailedEvent, x => x.CorrelateById(context => context.Message.LinkId));
Event(() => RequestLinkFailedEvent, x => x.CorrelateById(context => context.Message.LinkId));

Request(() => LinkRequest, x => x.UrlRequestId, cfg =>
{
            cfg.ServiceAddress = new Uri($"{hostAddress}/{nameof(SelectUrlByPublicId)}");
            cfg.SchedulingServiceAddress = new Uri($"{hostAddress}/{nameof(SelectUrlByPublicId)}");
            cfg.Timeout = TimeSpan.FromSeconds(30);
});

值得注意的是,我的 LinkId 始终是唯一的 Guid,因为它是在发送消息之前在控制器中创建的。

此外,当我重新启动应用程序池时,它会在第一次调用时再次工作,然后再次开始超时。

我觉得有些东西可能锁定在某个地方,但我无法在本地复制它!

所以我想post在这里解决我自己的问题,希望它能在将来帮助其他人。

我做了 3 项基本更改,单独或组合解决了这个问题,现在无论我使用 InMemorySagaRepository、Redis 还是 MongoDB。

第 1 期

正如我在此处 post 编辑的另一个问题中所述:

在我的 SagaStateMachineInstance class 中,我错误地将 CurrentState 属性 声明为 'State' 类型,而它本应是这样的字符串:

public string CurrentState { get; set;}

这是一个基本问题,当我开始尝试添加持久性时它就被发现了,所以它可能在使用 InMemorySagaRepository 时也造成了麻烦。

第 2 期

事后看来,我怀疑这可能是我的主要问题,我不完全相信我已经以最好的方式解决了它,但我对事情的现状很满意。

我确保我的最终活动在所有州都得到管理。我认为发生的事情是我的 request/response 在 saga 的 CurrentState 更新之前完成。我意识到这是通过尝试使用 MongoDB 作为我的坚持并看到我的 sagas 没有完成卡在倒数第二个状态。

第 3 期

这应该是不必要的,但我想将它添加到 consider/try 以供遇到问题的人使用。

我从 saga 中删除了 request/response 步骤,并将其替换为 publish/subscribe。为此,我向我的消费者发布了一个事件,该事件在完成时发布了一个带有 CorrelationId 的事件(正如@alexey-zimarev 在我的另一期中所建议的那样)。因此,在执行查询(即 reuqest)的消费者中,我在完成后执行以下操作:

context.Publish(new LinkCreatedEvent { ... , CorrelationId = context.Message.CorrelationId })

因为 CorrelationId 在那里,所以我的 saga 将它捡起来并这样处理事件:

When(LinkCreatedEvent )
   .ThenAsync(HandleLinkCreatedEventAsync)
   .TransitionTo(LinkCreated)

我对它现在的工作方式非常满意,并且对将解决方案投入使用充满信心。