如何处理长时间运行的订阅线程中的异常并从中恢复

本文关键字:何处理 线程 异常 恢复 处理 长时间 运行 | 更新日期: 2023-09-27 18:04:14

我正在使用ServiceStack。Redis在几个ASP。NET MVC应用程序,以促进这些应用程序之间的基本消息传递。在一个应用程序中,我有一个类,它设置订阅并处理应用程序感兴趣的任何消息,例如:

public MessageBus(IRedisClientsManager redisClientsManager)
{
    Thread subscriptionThread = new Thread(() => {
        try
        {
            using (var redisClient = redisClientsManager.GetClient())
            using (var subscription = redisClient.CreateSubscription())
            {
                subscription.OnMessage = (channel, message) =>
                {
                    handleMessage(message);
                };
                subscription.SubscribeToChannels("MyChannel");
            }
        }
        catch (Exception ex)
        {
            ErrorLog.GetDefault(null).Log(new Error(ex));
        }
    });
    subscriptionThread.Start();
}

因为"SubscribeToChannels"是阻塞的,我让它在一个单独的线程中运行。我希望这个线程在MVC应用程序运行的整个时间里都保持活跃,我担心线程会死,或者如果发生任何异常,到Redis的连接会停止。

我的问题是:是否有任何例子,如何从异常(连接失败,超时等)中恢复,而订阅是开放的?

如何处理长时间运行的订阅线程中的异常并从中恢复

对于终止线程的异常,使用长时间运行的循环:

while(!ShutdownRequested) {
    try{...}
    catch(Exception e) {/*Log and probably do some rate-limiting in case of terminal issue*/}
}

请记住,catch将吞噬所有内容,包括OutOfMemory异常,因此您将需要一些完整性检查,如失败计数/延迟,这样您就不会总是立即重试。

不要忘记,你可以从父线程中保留对后台线程的引用,也可以检查ThreadState。

至于在ASP中托管,这是一个坏主意(参见这个答案)。当工作池被回收(最终会发生)时,线程将死亡,直到请求新页面(最早)才会重生。

你应该把它放到一个windows服务中,这样它就可以在服务器启动时运行,如果它必须与你的站点通信,它应该通过WCF (2-way)或通过点击Url(从服务推送到站点)来完成。

这样,它只会在服务停止时死亡(希望只是重新启动)。