ForcePilot/backend/package/yuxi/scheduler/use_cases/utils/backoff.py

70 lines
2.4 KiB
Python
Raw Normal View History

"""指数退避计算工具。
本模块提供两个函数
- ``calc_backoff_seconds``根据连续错误数从退避序列取退避秒数
- ``calc_backoff_next_run_at``计算退避后的下次运行时间
设计要点见设计方案 §8.2
- 退避序列由配置 ``scheduler_backoff_schedule`` 提供 ``[10, 30, 120, 600, 3600]``
- 根据 ``consecutive_errors`` 从序列取值超过序列长度时取最后一个值
- ``consecutive_errors`` 0 时返回 0无退避
- 时间计算基于 ``utc_now_naive()``结果为 UTC naive datetime
- 纯函数不依赖框架层组件
"""
from __future__ import annotations
from datetime import datetime, timedelta
from yuxi.utils.datetime_utils import utc_now_naive
def calc_backoff_seconds(consecutive_errors: int, schedule: list[int]) -> int:
"""根据连续错误数计算退避秒数。
Args:
consecutive_errors: 连续错误次数
schedule: 退避时间表 ``[60, 300, 1800, 7200]``
Returns:
退避秒数超过 ``schedule`` 长度时取最后一个值
说明:
- ``consecutive_errors <= 0`` 时返回 0无退避
- ``consecutive_errors`` ``[1, len(schedule)]`` 范围内时
``schedule[consecutive_errors - 1]``
- ``consecutive_errors`` 超过序列长度时 ``schedule[-1]``封顶
- ``schedule`` 为空时返回 0
"""
if consecutive_errors <= 0 or not schedule:
return 0
index = min(consecutive_errors, len(schedule)) - 1
return schedule[index]
def calc_backoff_next_run_at(
consecutive_errors: int,
schedule: list[int],
*,
base_time: datetime | None = None,
) -> datetime:
"""计算退避后的下次运行时间。
Args:
consecutive_errors: 连续错误次数
schedule: 退避时间表
base_time: 基准时间UTC naive默认 ``utc_now_naive()``
Returns:
UTC naive datetime退避后的下次运行时间
说明:
``consecutive_errors`` 0 时退避秒数为 0返回 ``base_time``
或当前 UTC 时间
"""
base = base_time if base_time is not None else utc_now_naive()
seconds = calc_backoff_seconds(consecutive_errors, schedule)
return base + timedelta(seconds=seconds)