Celery + Docker + Django - 让任务开始工作

时间:2015-09-20 20:15:00

标签: django celery docker-compose

过去一周我一直在努力学习Celery并将其添加到使用Django和Docker-Compose的项目中。我很难理解如何让它发挥作用;我的问题是,在使用任务时我似乎无法上传到我的数据库。上传功能insertIntoDatabase在没有任何Celery参与之前工作正常,但现在上传不起作用。事实上,当我尝试上传时,我的网站太快告诉我上传成功了,但实际上并没有上传任何内容。

服务器以docker-compose up启动,这将进行迁移,执行迁移,收集静态文件,更新要求,然后启动服务器。这都是使用pavement.py完成的; Dockerfile中的命令是CMD paver docker_run。芹菜工人从未明确地开始过;我应该这样做吗?如果是这样,怎么样?

这是我在views.py中调用上传功能的方式:

insertIntoDatabase.delay(datapoints, user, description)

上传功能在名为databaseinserter.py的文件中定义。以下装饰器用于insertIntoDatabase

@shared_task(bind=True, name="database_insert", base=DBTask)

以下是DBTaskcelery.py类的定义:

class DBTask(Task):
     abstract = True

     def on_failure(self, exc, *args, **kwargs):
        raise exc

我不确定要为tasks.py撰写什么。以下是我离开之前离开的前同事所留下的东西:

from celery.decorators import task
from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

@task(name="database_insert")
def database_insert(data):

以下是我用来配置Celery(settings.py)的设置:

BROKER_TRANSPORT = 'redis'
_REDIS_LOCATION = 'redis://{}:{}'.format(os.environ.get("REDIS_PORT_6379_TCP_ADDR"), os.environ.get("REDIS_PORT_6379_TCP_PORT"))
BROKER_URL = _REDIS_LOCATION + '/0'
CELERY_RESULT_BACKEND = _REDIS_LOCATION + '/1'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ENABLE_UTC = True
CELERY_TIMEZONE = "UTC"

现在,我猜测database_insert中的tasks.py不应为空,但应该去哪里呢?此外,它似乎不会发生tasks.py中的任何事情 - 当我添加一些日志记录语句以查看tasks.py是否至少被运行时,实际上没有任何结果记录,让我认为tasks.py甚至没有被运行。如何正确地将上传功能转换为任务?

1 个答案:

答案 0 :(得分:2)

我认为你离这项工作并不太远。

首先,我建议您尝试将Celery任务和业务逻辑分开。因此,例如,在insertIntoDatabase函数中将数据插入数据库所涉及的业务逻辑可能是合理的,然后单独创建一个Celery任务,可能是名称insert_into_db_task,在您的args中作为普通的python对象(重要)并使用这些args调用前面提到的insertIntoDatabase函数来实际完成数据库插入。

该示例的代码可能如下所示:

程序my_app /任务/ insert_into_db.py

from celery.decorators import task
from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

@task()
def insert_into_db_task(datapoints, user, description):
    from my_app.services import insertIntoDatabase
    insertIntoDatabase(datapoints, user, description)

my_app应用/服务/ insertIntoDatabase.py

def insertIntoDatabase(datapoints, user, description):
    """Note that this function is not a task, by design"""

    # do db insertion stuff

程序my_app /视图/ insert_view.py

from my_app.tasks import insert_into_db_task

def simple_insert_view_func(request, args, kwargs):
    # start handling request, define datapoints, user, description

    # next line creates the **task** which will later do the db insertion
    insert_into_db_task.delay(datapoints, user, description)
    return Response(201)

我暗示的应用程序结构就是我如何做到而不是必需的。另请注意,您可以直接使用@task(),而不是为它定义任何参数。可以为你简化一些事情。

这有帮助吗?我喜欢让我的任务轻松蓬松。他们大多只是进行混蛋校对(例如确保所涉及的obj存在于DB中),调整如果任务失败(稍后重试?中止任务等等),日志记录以及执行其他地方的业务逻辑时会发生什么。

此外,如果不明显,您需要在某处运行芹菜,以便有工作人员实际处理您的视图代码正在创建的任务。如果您没有在某处运行芹菜,那么您的任务将在队列中堆叠起来并且永远不会被处理(因此您的数据库插入将永远不会发生)。