Docker Compose设置restart:on-failure,Jobs容器为何重启时自动启动?
为什么系统重启时Jobs容器自动启动而API容器不会?
核心原因在于restart: on-failure的重启规则,加上两个容器进程的退出行为存在差异:
1. Docker on-failure 重启策略的逻辑
这个重启策略仅在容器进程以非零退出码异常终止时,才会触发自动重启。如果容器是被正常停止(比如docker stop、系统关机时的优雅停止,退出码为0),系统重启后Docker不会主动启动该容器。
2. Jobs容器的进程退出行为
你的job.py通过asyncio.run()运行包含无限循环的异步任务,默认情况下Python的asyncio框架不会处理SIGTERM/SIGINT这类终止信号。当系统关机时,Docker会向容器发送SIGTERM信号尝试优雅停止,但Jobs容器内的Python进程无法捕获该信号,最终会被Docker强制杀死,退出码为非0值。这种异常退出刚好符合on-failure的重启条件,因此系统重启后Jobs容器会自动启动。
3. API容器的进程退出行为
Uvicorn作为标准的ASGI服务器,默认会处理SIGTERM等终止信号,收到信号后会优雅关闭服务,进程以退出码0正常终止。这种正常退出不满足on-failure的重启触发条件,所以系统重启后API容器不会自动启动。
解决办法
如果你希望系统重启时两个容器都自动启动,建议将重启策略改为restart: always或者restart: unless-stopped:
always:无论容器以何种状态退出,只要不是被手动停止,都会自动重启unless-stopped:和always逻辑类似,但如果是手动执行docker stop停止的容器,系统重启后不会自动启动
修改后的compose.yml片段:
api: restart: unless-stopped command: uvicorn app:app ... jobs: restart: unless-stopped command: python job.py ...
如果坚持使用on-failure策略,可以给Jobs容器的Python进程添加信号处理逻辑,确保收到终止信号时优雅退出(退出码0),这样系统重启后它也不会自动启动。示例代码如下:
import asyncio import signal from prometheus_client import start_http_server async def background(sio): await asyncio.gather(...) # 你的无限循环任务 async def main(): loop = asyncio.get_running_loop() # 注册信号处理,收到终止信号时停止事件循环 for sig in [signal.SIGTERM, signal.SIGINT]: loop.add_signal_handler(sig, lambda: asyncio.create_task(loop.stop())) start_http_server(5000) await background(sio) if __name__ == "__main__": asyncio.run(main())
内容的提问来源于stack exchange,提问作者Alex Poloz
相关产品推荐
相关产品推荐

