初始提交:chongming-task 任务控制库
单任务受控执行(15 态状态机 + 审计轨迹)、DAG 管道、Controller 门面。
执行器三个:线程(默认,含 async def 任务)、内联(同步 / 测试)、进程
(spawn 子进程:硬性停止、绕开 GIL、崩溃隔离)。
调度:并发额度 + 每桶限流 + 具名资源信号量(按标签)+ 优先级排队。
持久层:TaskStore 契约 + 内存 / SQLite / Postgres 实现,契约测试随包发布。
跨进程与多节点:写穿 / 读穿、指令通道与租约、owned_buckets 划界、reconcile。
CLI、12 个可直接运行的示例、docs/ 下 5 份文档。
门禁:ruff / ruff format / mypy(strict) 干净;
pytest 563 passed(44 skipped 是需要真实 Postgres 的那批);
带一台可连的 Postgres 时 607 passed。
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
"""示例 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()
|
||||
Reference in New Issue
Block a user