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

如何在Ubuntu平台从Celery任务内部关闭Django Celery Worker

在Celery任务内关闭Ubuntu上的Worker(Django环境)

嘿,我来给你梳理几个在Django环境下,从Celery任务内部关闭Ubuntu上Celery Worker的可行方案,你可以根据自己的场景挑合适的:

方案1:用Celery原生控制API(最规范)

Celery自带了控制Worker的API,app.control.shutdown()可以优雅地关闭Worker,避免暴力终止导致的任务丢失,这也是官方推荐的方式。

代码示例:

from celery import current_app
from celery.task.control import inspect

def my_shutdown_task():
    # 先执行你的任务逻辑
    # ...
    
    # 获取当前运行任务的Worker标识(确保只关闭当前Worker,而非所有集群节点)
    insp = inspect()
    worker_info = insp.active_queues()
    if worker_info:
        current_worker_id = list(worker_info.keys())[0]
        # 定向关闭该Worker
        current_app.control.shutdown(destination=[current_worker_id])
    else:
        # 降级方案:如果无法获取Worker ID,关闭所有Worker(谨慎使用)
        current_app.control.shutdown()

注意事项:

  • 这个方法会让Worker优雅退出:先完成当前正在执行的任务,再停止接收新任务并退出。
  • 如果你的Worker是集群模式,一定要用destination参数指定目标Worker,否则会关闭所有节点。
  • 确保Worker启动时没有禁用控制功能(比如没加--without-heartbeat这类限制参数)。

方案2:直接调用系统命令(简单粗暴)

在Ubuntu上,Celery Worker是系统进程,你可以在任务里通过pkill或kill命令直接终止进程,适合场景简单、不需要严格优雅关闭的情况。

代码示例:

方式A:关闭所有Celery Worker(谨慎使用)

import subprocess

def my_task():
    # 任务逻辑
    # ...
    
    # 用pkill匹配进程名,发送SIGTERM信号优雅关闭(换成-9就是强制终止)
    subprocess.run(["pkill", "-f", "celery worker"], check=False)

方式B:只关闭当前任务所在的Worker

import os
import signal

def my_task():
    # 任务逻辑
    # ...
    
    # 获取当前任务所在的Worker进程PID
    worker_pid = os.getpid()
    # 发送SIGTERM信号优雅关闭
    os.kill(worker_pid, signal.SIGTERM)
    # 如果需要强制终止,改用signal.SIGKILL
    # os.kill(worker_pid, signal.SIGKILL)

注意事项:

  • 要确保运行任务的进程有足够权限杀死Worker进程(比如不要用低权限用户启动Celery)。
  • SIGTERM(信号15)会让Worker完成当前任务再退出,SIGKILL(信号9)会直接强制终止,可能丢失未完成的任务。
  • pkill -f会匹配所有包含"celery worker"的进程,如果你有其他同名进程会误杀,要确保进程名唯一。

方案3:标记触发Worker自动退出(优雅且灵活)

如果希望Worker完成当前任务后再退出,又不想直接调用关闭命令,可以设置一个退出标记,让Worker的启动脚本检测到标记后停止重启。

步骤1:任务中设置标记(以Redis为例)

import redis
from django.conf import settings

def my_task():
    # 任务逻辑
    # ...
    
    # 连接Redis,设置退出标记
    r = redis.Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT)
    r.set("celery_worker_shutdown_flag", "1")

步骤2:修改Worker启动脚本(bash)

把原来直接启动Celery的命令改成循环检测标记的脚本:

#!/bin/bash
while true; do
    # 启动Celery Worker
    celery -A your_django_project worker --loglevel=info
    # 检查Redis中的退出标记
    if redis-cli get celery_worker_shutdown_flag; then
        # 删除标记并退出循环
        redis-cli del celery_worker_shutdown_flag
        break
    fi
    # 如果没有标记,可选重启Worker(根据你的需求调整)
    sleep 5
done

注意事项:

  • 这个方案适合需要Worker“完成当前任务后再退出”的场景,完全不会中断正在执行的任务。
  • 依赖Redis传递标记,你也可以用本地文件、数据库等替代。

内容的提问来源于stack exchange,提问作者Omroth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 14:57:28