Python:将异常从 paho (MQTT) 线程传播到主线程

Python: propagate exceptions from paho (MQTT) thread to the main thread

提问人:Gauthier 提问时间:11/9/2023 更新时间:11/16/2023 访问量:33

问:

我有一个 python 应用程序,它使用线程从 MQTT 代理接收主题,并监控 UART 上的消息。在 Raspberry Pi 上运行。

paho MQTT 库的接口提供回调来处理接收消息,并且 a 显然会启动一个新线程然后返回。loop_start()

我的问题是我希望接收回调中可能出现的异常一直提升到应用程序的“顶部”,以便我可以干净地终止整个应用程序。

就像现在一样,paho 线程中的异常会终止该线程,但其他线程保持活动状态,并且应用程序正在运行但无法正常工作。这很糟糕,我指望 systemd 服务重新启动崩溃的应用程序,这就是为什么我需要它真正崩溃的原因。

我已经为UART RX线程做了这个:

class MyClassError(Exception):
    def __init__(self, message):
        self.message = f"{message}"
        super().__init__(self.message)


class MyClass()::
    # other stuff...
    def rx(self):
        try:
            while True:
                do_your_thing()
        except Exception as e:
            self.exc = MyClassError(f"An unexpected error occurred: {e}")
            return

    def run(self):
        self.rx_thread.start()
        self.rx_thread.join()
        if self.exc is not None:
            raise self.exc

,这有效,但需要注意的是它不会返回。但我可以在调用方线程中捕获异常。

还有其他方法可以达到类似的效果,例如 // 在回调代码中,或者让主线程监控 paho 线程的状态......但感觉我应该能够在子线程中引发异常,并在父线程中捕获它们。tryexceptsys.exit(1)

此外,我想捕获并引发任何 MQTT 代码中的任何异常,而不仅仅是该特定回调。但这是第 2 步。

如何将 paho 库中发生的异常(或它调用的回调)升级到主线程,以便它可以终止所有内容?

Python 多线程 异常 PAHO

评论

1赞 Solomon Slow 11/9/2023
“感觉我应该能够在子线程中引发异常,并在父线程中捕获它们。”引发异常实际上只不过是函数返回给其调用方的另一种方式。异常对象是一种特殊类型的返回值,不能忽略。您不能在一个线程中引发异常并在另一个线程中捕获它,原因与不能在一个线程中调用函数并在另一个线程中返回函数的原因相同。也许您可以设置一个标志并为主线程编写代码来检查它,如果设置了它,则引发异常。
0赞 Gauthier 11/10/2023
谢谢! 似乎做了我想做的事。threading.excepthook

答:

0赞 Gauthier 11/16/2023 #1

我目前的解决方案是以这种方式在顶层捕获未捕获的异常:


def handle_exceptions(e):
    try:
        my_object.stop()
    except Exception as e:
        print(e)
    try:
        mqtt_manager.stop()
    except Exception as e:
        print(e)
    print(traceback.print_exception(e.exc_type, e.exc_value, e.exc_traceback))

threading.excepthook = handle_exceptions

MQTT 循环在此停止后需要几秒钟才能消失(我想知道为什么?循环是否只在下一个事件中死亡?),但整个应用程序最终都会死亡。