asyncio.create_task() 配合 asyncio.sleep() 是最轻量的定时方案;需用 await asyncio.sleep() 替代 time.sleep(),设间隔30秒,用 httpx.asyncclient 封装监控协程,捕获 cancellederror 清理资源,并显式处理 sigint 信号确保优雅退出。

asyncio.create_task() 配合 asyncio.sleep() 是最轻量的定时方案
Python 3.12 的 asyncio 已稳定支持结构化并发,不用再手动管理 Task 生命周期。直接用 asyncio.create_task() 启动一个无限循环协程即可,比 loop.call_later() 更直观、更易取消。
关键点在于:每次检查后必须用 await asyncio.sleep(interval),不能用 time.sleep()——后者会阻塞整个事件循环。
- 推荐间隔设为
30.0(秒),太短容易触发服务器限流,太长(如 >120)可能错过故障窗口 - 用
asyncio.wait_for()包裹 HTTP 请求,防止某次超时拖垮后续轮询 - 把监控逻辑封装成独立协程(如
check_server_health()),方便单元测试和复用
用 httpx.AsyncClient 替代 requests,避免阻塞事件循环
requests 是同步库,即使在 async def 里调用也会让整个协程“卡住”。Python 3.12 下必须选原生异步 HTTP 客户端,httpx.AsyncClient 是目前最成熟的选择。
注意默认不启用连接池复用,需显式传参:
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
async with httpx.AsyncClient(timeout=10.0, limits=httpx.Limits(max_connections=20)) as client:
resp = await client.get("https://api.example.com/health")
- 务必设置
timeout,否则 DNS 失败或服务无响应会导致任务永久挂起 -
limits参数控制并发连接数,监控多个端点时避免耗尽本地端口 - 不要在循环外创建长期存活的
AsyncClient实例——它不是线程安全的,且内部连接池可能因服务端 Keep-Alive 超时失效
捕获 CancelledError 并做清理,否则定时任务无法优雅退出
当主程序收到 SIGINT(Ctrl+C)或调用 task.cancel() 时,运行中的协程会抛出 asyncio.CancelledError。如果没捕获,日志里只看到 “Task was destroyed but it is pending!”,资源(如 TCP 连接、文件句柄)可能泄漏。
- 在主循环里用
try/except asyncio.CancelledError:包裹,执行关闭逻辑(如记录最后状态、发告警)后再raise - HTTP 客户端实例应放在
async with块内,确保异常时自动关闭连接 - 避免在
finally块里写await操作——被取消的协程不允许再 await 新的 awaitable
别忽略信号处理和多任务协同,否则 Ctrl+C 会杀不掉进程
Python 3.12 默认不会把 SIGINT 传给事件循环,直接按 Ctrl+C 只会中断当前正在 await 的操作,主循环还在跑。必须显式添加信号处理器。
典型做法是:启动一个 asyncio.Task 监听 asyncio.run() 返回的 loop,并在信号触发时取消所有监控任务:
def signal_handler():
for task in asyncio.all_tasks():
if task.get_coro().__name__ == "monitor_loop":
task.cancel()
loop = asyncio.get_running_loop()
loop.add_signal_handler(signal.SIGINT, signal_handler)
- 用
asyncio.all_tasks()获取全部任务,比维护全局列表更可靠 - 检查
task.get_coro().__name__来区分监控任务和其他后台任务(如日志上传) - 如果使用
asyncio.run(main())启动,记得在main()结尾加await asyncio.sleep(0.1),给取消传播留出时间
异步定时监控真正的难点不在“怎么发起请求”,而在于“怎么让它该停就停、该报错就报错、该重试就重试”——尤其是网络抖动时,CancelledError 和 TimeoutError 的交织很容易漏掉清理路径。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










