You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 23:57:21