实现重试装饰器一种高于异常的方法

Implementing retry decorator one method higher than exception

我正在尝试对串行查询实施 retry decorator。我的代码的总体思路如下所示。当装饰器是层次结构中的一种方法时,我正在努力让它重试。当它是抛出异常的方法的上一个方法时,如何重试该方法?

一个令人沮丧的并发症是我每次重试的增量时间取决于实际命令。有些命令比其他命令需要更多时间。这就是为什么我传入了 extra_time_per_retry,并且无法使用传统的 @retry 样式实现重试装饰器。

仅供参考,_serial 是通过 pySerial 在 init 上的 class 中创建的。

我让它与抛出异常的方法正上方的重试装饰器一起工作。我希望它在上面两个以保持我的代码干净。

我已经尝试为重试装饰器提供确切的异常类型,但无法让它工作。

def _query_with_retries(self, cmd, extra_time_per_retry):
    _retriable_query = retry(stop_max_attempt_number=5,
                             wait_incrementing_start=self._serial.timeout + extra_time_per_retry,
                             wait_incrementing_increment=10)(self._query)
    return _retriable_query(cmd)

def _query(self, cmd):
    cmd_msg = cmd + '\r'
    self._serial.reset_input_buffer()
    self._serial.reset_output_buffer()
    self._serial.write(cmd_msg)

    return self._readlines()

def _readlines(self):
    response_str = self._serial.read_until('\r', 256)  # Max 256 bytes

    # Parse response here, if a bad one set bad_response = true

    if bad_response:
        raise ResponseError("Response had custom error xyz")

我想您可以将对 _readlines() 的调用打包到异常处理块中,重新引发错误:

python 3.x

@retry
def _query(self, cmd):
    cmd_msg = cmd + '\r'
    self._serial.reset_input_buffer()
    self._serial.reset_output_buffer()
    self._serial.write(cmd_msg)

    try:
        answer = self._readlines()
    except Exception as e:
        raise e
    return answer

python 2.x

@retry
def _query(self, cmd):
    cmd_msg = cmd + '\r'
    self._serial.reset_input_buffer()
    self._serial.reset_output_buffer()
    self._serial.write(cmd_msg)

    try:
        answer = self._readlines()
    except Exception:
        t, v, tb = sys.exc_info()
        raise t, v, tb
    return answer

这样,您可以在异常发生时直接捕获异常,并在将重试的方法中引发它。我不确定这对你来说是否足够整洁,但它应该有效。

有些人可能会抱怨使用空白 except Exception,但是因为我总是立即重新加注,所以我看不出有什么坏处。