如何在另一个进程锁定表时暂停 Rebus 执行

How to suspend Rebus execution while another process is locking tables

我需要执行两个 API 来暂停和重新激活 Rebus 出队过程。

情况是服务总线Rebus和另一个软件共享同一个数据库和tables来存储应用程序数据(不是队列),但是后者软件(姑且称之为"Xprocess"), 在一天中的某个特定时刻,锁定一些 table 大约 3 分钟。由于 Xprocess 优先于 Rebus 消息执行,我们同意在此间隔期间通过 Xprocess 调用的 Suspend 和 Resume api 暂停 Rebus。

我正在徘徊哪种是暂停 Rebus 消息执行的最佳方式。 考虑到不可能添加暂停后续消息的特定消息,因为当 Xprocess 启动时,队列中可能已经有一些必须暂停的消息;

我的想法是在调用下一步之前在接收管道中添加一个询问 "Pausing" 服务的步骤。 像这样:

public class HandlePausingServiceStep : IIncomingStep
{
    readonly ILog _log;
    readonly IPausingService _pausingService;

    public HandlePausingServiceStep(IRebusLoggerFactory rebusLoggerFactory, IPausingService pausingService)
    {
        _log = rebusLoggerFactory.GetLogger<HandleApplicationExceptionsStep>();
        _pausingService = pausingService;
    }

    public async Task Process(IncomingStepContext context, Func<Task> next)
    {
        while (_pausingService.Pause)
            Thread.Sleep(5000);

        await next();
    }
}

在做任何其他事情之前,我会考虑以下两个选项:

1) 只需在数据库锁定期间停止托管您的 Rebus 端点的进程。

如果您的端点托管为 Windows 服务(在许多情况下它可能应该如此),您可以简单地制作一个脚本 net stop YourService/net start YourService 并使用 Windows' Task Scheduler 来完成它。

2) 使用Rebus的thread worker API 设置worker数量为0.

你可以这样做:

bus.Advanced.Workers.SerNumberOfWorkers(0);

然后是时候再次做事了:

bus.Advanced.Workers.SerNumberOfWorkers(5);

但显然您不应该从 Rebus 处理程序执行此操作(因为它将如何获得再次唤醒它的消息?:D)

就我个人而言,我更喜欢第一个选项,因为它非常简单并且易于操作人员管理。


更新:在意识到这个总线托管在 Web 应用程序的多个实例中之后,我想我会以稍微不同的方式解决这个挑战...

我认为 acceptable 的解决方案是在 Web 应用程序的后台设置一个计时器,定期检查数据库中特殊 table 中的配置标志值 - 这是可以做到的每 5-10 秒左右。

然后当标志被发出信号时,所有实例都会SetNumberOfWorkers(0),从而有效地停止所有消息处理。

当flag再次升起时,计时器可以重新添加worker。

如果在数据库锁定时不进行任何消息处理这一点很重要,那么在 raising/lowering 标志周围添加一点时间余量可能很重要。