过去一周我一直在努力学习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)
以下是DBTask
中celery.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
甚至没有被运行。如何正确地将上传功能转换为任务?
答案 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中),调整如果任务失败(稍后重试?中止任务等等),日志记录以及执行其他地方的业务逻辑时会发生什么。
此外,如果不明显,您需要在某处运行芹菜,以便有工作人员实际处理您的视图代码正在创建的任务。如果您没有在某处运行芹菜,那么您的任务将在队列中堆叠起来并且永远不会被处理(因此您的数据库插入将永远不会发生)。