Skip to main content
 首页 » 编程设计

python之奇怪的 Docker + Celery Bug

2024年08月21日30傻小

我正在尝试在 docker 容器中运行 celery,但由于某种原因它从不更新。每当我在 tasks.py 中添加新函数或更新现有函数时,即使在我重新启动容器后,它也永远不会向 celery 注册。

这是我的dockerfile:

# start with a base image 
FROM python:3.4-slim 
 
ENV REDIS_IP 1.1.1.111 
ENV REDIS_PORT 6379 
ENV REDIS_DB 0 
 
# install dependencies 
RUN apt-get update && apt-get install -y \ 
apt-utils \ 
nginx \ 
supervisor \ 
python3-pip \ 
&& rm -rf /var/lib/apt/lists/* 
 
RUN echo "America/New_York" > /etc/timezone; dpkg-reconfigure -f noninteractive tzdata 
 
# update working directories 
ADD ./app /app 
ADD ./config /config 
ADD requirements.txt / 
 
# install dependencies 
RUN pip install --upgrade pip 
RUN pip3 install -r requirements.txt 
 
# setup config 
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf 
RUN rm /etc/nginx/sites-enabled/default 
 
RUN ln -s /config/nginx.conf /etc/nginx/sites-enabled/ 
RUN ln -s /config/supervisor.conf /etc/supervisor/conf.d/ 
 
EXPOSE 80 
CMD ["supervisord", "-n"] 

然后是我的supervisor.conf:

[program:app] 
command = uwsgi --ini /config/app.ini 
autostart=true 
autorestart=true 
 
[program:nginx] 
command = service nginx restart 
autostart=true 
autorestart=true 
 
[program:celery] 
directory = /app 
command = celery -A tasks.celery worker -P eventlet -c 1000 
autostart=true 
autorestart=true 

我的tasks.py:

import os 
from celery import Celery 
from app import app as flask_app 
 
def make_celery(app): 
    celery = Celery(app.import_name, backend='redis://{0}:{1}/{2}'.format(os.environ['REDIS_IP'],os.environ['REDIS_PORT'],os.environ['REDIS_DB']), 
                    broker='redis://{0}:{1}/{2}'.format(os.environ['REDIS_IP'],os.environ['REDIS_PORT'],os.environ['REDIS_DB'])) 
    celery.conf.update( 
        CELERY_ENABLE_UTC=True, 
        CELERY_TIMEZONE='America/New_York' 
    ) 
    TaskBase = celery.Task 
    class ContextTask(TaskBase): 
        abstract = True 
        def __call__(self, *args, **kwargs): 
            with app.app_context(): 
                return TaskBase.__call__(self, *args, **kwargs) 
    celery.Task = ContextTask 
    return celery 
 
celery = make_celery(flask_app) 
 
@celery.task() 
def add_together(a, b): 
    return a+ b 
 
@celery.task() 
def multiply(a,b) 
    return a*b 

出于某种原因:

  • 我有 21 名 worker 注册了,但 multiply 从未注册过,
  • 同样,当我对 add_together 进行更改时,它也永远不会注册,即使我重新启动容器也是如此。

我开始我的容器:

docker build --rm -t myapp . 
docker run -d -p 88:80 -v $(pwd)/app:/app --name=myapp myapp 

并重新启动:

docker restart myapp 

我也试过

docker stop $(docker ps -a -q) 
docker rm $(docker ps -a -q) 

然后重新构建应用程序。没有任何帮助。任何想法将不胜感激。

请您参考如下方法:

我认为这可能是问题所在:

@celery.task()  # <-- you shouldn't call this decorator directly 
def add_together(a, b): 
    return a+ b 

尝试将其更改为:

@celery.task 
def add_together(a, b): 
    return a+ b 

原因:只需检查 source code of decorator task :

def task(self, *args, **opts): 
    """Creates new task class from any callable.""" 
 
    # ... handling named options 
 
    if len(args) == 1: 
        if callable(args[0]): 
            return inner_create_task_cls(**opts)(*args) 
        raise TypeError('argument 1 to @task() must be a callable') 
    if args: 
        raise TypeError( 
            '@task() takes exactly 1 argument ({0} given)'.format( 
                sum([len(args), len(opts)]))) 
    return inner_create_task_cls(**opts) 

它接受的唯一未命名参数是要修饰的函数。否则它会引发 TypeError 并被 supervisord 吞没,因为你没有配置 the loglevel to debug .