87 lines
2.4 KiB
Python
87 lines
2.4 KiB
Python
"""示例 3:重试与超时。
|
||||
|
|
|
|||
|
|
运行::
|
|||
|
|
|
|||
|
|
uv run python examples/03_retry_and_timeout.py
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import time
|
|||
|
|
|
|||
|
|
from chongming_task.policies import ExponentialBackoff, RetryPolicy, Timeout
|
|||
|
|
from chongming_task.run import run_task
|
|||
|
|
|
|||
|
|
_attempts = 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
def flaky(ctx, succeed_on_attempt: int) -> str:
|
|||
|
|
"""前几次故意失败,用来演示重试与退避。"""
|
|||
|
|
global _attempts
|
|||
|
|
_attempts += 1
|
|||
|
|
if _attempts < succeed_on_attempt:
|
|||
|
|
raise RuntimeError(f"第 {_attempts} 次尝试遇到暂时性故障")
|
|||
|
|
return f"第 {_attempts} 次尝试成功"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def slow(ctx) -> str:
|
|||
|
|
"""跑得很慢,用来演示超时后会被请求停止。"""
|
|||
|
|
for _ in range(10_000):
|
|||
|
|
ctx.checkpoint()
|
|||
|
|
time.sleep(0.01)
|
|||
|
|
return "跑完了"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def demo_retry() -> None:
|
|||
|
|
print("== 重试:失败两次后成功 ==")
|
|||
|
|
_attempts = 0
|
|||
|
|
outcome = run_task(
|
|||
|
|
flaky,
|
|||
|
|
3,
|
|||
|
|
retry=RetryPolicy(max_attempts=5, backoff=ExponentialBackoff(base=0.05, factor=2)),
|
|||
|
|
task_id="demo-retry",
|
|||
|
|
name="会抖的任务",
|
|||
|
|
)
|
|||
|
|
print(f" 终态 :{outcome.status.value}")
|
|||
|
|
print(f" 返回值 :{outcome.value}")
|
|||
|
|
print(f" 尝试次数 :{outcome.snapshot.attempt}/{outcome.snapshot.max_attempts}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def demo_retry_exhausted() -> None:
|
|||
|
|
print("\n== 重试:预算耗尽 ==")
|
|||
|
|
global _attempts
|
|||
|
|
_attempts = 0
|
|||
|
|
outcome = run_task(
|
|||
|
|
flaky,
|
|||
|
|
99, # 永远不会成功
|
|||
|
|
retry=RetryPolicy(max_attempts=2, backoff=ExponentialBackoff(base=0.05, factor=1)),
|
|||
|
|
task_id="demo-exhausted",
|
|||
|
|
name="必定失败",
|
|||
|
|
)
|
|||
|
|
print(f" 终态 :{outcome.status.value}")
|
|||
|
|
print(f" 尝试次数 :{outcome.snapshot.attempt}/{outcome.snapshot.max_attempts}")
|
|||
|
|
print(f" 失败归类 :{outcome.failure.kind.value if outcome.failure else '-'}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def demo_timeout() -> None:
|
|||
|
|
print("\n== 超时:单次尝试不超过 0.5 秒 ==")
|
|||
|
|
outcome = run_task(
|
|||
|
|
slow,
|
|||
|
|
timeout=Timeout(per_attempt=0.5),
|
|||
|
|
task_id="demo-timeout",
|
|||
|
|
name="慢任务",
|
|||
|
|
)
|
|||
|
|
print(f" 终态 :{outcome.status.value}")
|
|||
|
|
print(f" 失败归类 :{outcome.failure.kind.value if outcome.failure else '-'}")
|
|||
|
|
print(f" 可重试 :{outcome.failure.retryable if outcome.failure else '-'}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main() -> None:
|
|||
|
|
demo_retry()
|
|||
|
|
demo_retry_exhausted()
|
|||
|
|
demo_timeout()
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|