如何在代理类中处理不可用主机(ConnectionRefusedError)

3 投票
1 回答
7114 浏览
提问于 2025-04-18 22:49

我有一个非常基础的代理类(一个帮我写代码的朋友坚持认为它是一个装饰器类),用于 python-mpd2

这个类的样子是这样的:

import mpd

class MPDProxy:
    def __init__(self, host="localhost", port=6600, timeout=10):
        self.client = mpd.MPDClient()
        self.host = host
        self.port = port

        self.client.timeout = timeout
        self.connect(host, port)

    def __getattr__(self, name):
        return self._call_with_reconnect(getattr(self.client, name))

    def connect(self, host, port):
        self.client.connect(host, port)

    def _call_with_reconnect(self, func):
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except mpd.ConnectionError:
                self.connect(self.host, self.port)
                return func(*args, **kwargs)
        return wrapper

mpd_proxy = MPDProxy()

到目前为止,这个类工作得很好,只要有一个可用的mpd主机可以连接。如果没有mpd服务器,我会遇到:

ConnectionRefusedError: [Errno 111] 连接被拒绝

我在寻找处理这个异常的好方法。

  • 你能想到一个优雅的方式来防止程序崩溃吗,当没有可用的主机时?
  • 我应该在代理内部捕获这个异常,还是在每次调用代理时在外部捕获?
  • 返回一个字符串“主机不可用”(或类似的内容)作为返回值是个好主意吗,还是有更好的方法可以让调用代理的方法/函数知道?

1 个回答

3

你能想出一个优雅的方法来防止程序在没有主机可用时崩溃吗?

try ... except ;)


我应该在代理内部捕获异常,还是在每次调用代理时在外部捕获?

你应该问自己一个问题:"谁有能力处理这个异常?"


显然,代理无法做任何合理的事情来“修复”ConnectionRefusedError。所以这个问题必须在更高的层级处理。


返回一个字符串“主机不可用”(或类似的)作为返回值是个好主意吗?还是有更好的方法让调用代理的方法/函数知道?

这不是个好主意。通常通知“上层”发生了异常的方式是raise一个异常。或者让一个抛出的异常向上传播。


具体来说:

class MPDProxy:
    def _call_with_reconnect(self, func):
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except mpd.ConnectionError:
                self.connect(self.host, self.port)
                # ^^^^^^ This lime might raise `ConnectionRefusedError`
                # as there is no `except` block around, this exception
                # is automatically propagated     

                return func(*args, **kwargs)
        return wrapper

try:
    mpd_proxy = MPDProxy()
    r = mdp_proxy._call_with_reconnect(whatever)
except ConnectionRefusedError:
    do_somesible_sensible()

撰写回答