芹菜+;Docker&x2B;Django——让任务发挥作用

芹菜+;Docker&x2B;Django——让任务发挥作用,django,celery,docker-compose,Django,Celery,Docker Compose,在过去的一周里,我一直在尝试学习芹菜,并将其添加到使用Django和Docker Compose的项目中。我很难理解如何让它工作;我的问题是,在使用任务时,我似乎无法上传到我的数据库来工作。上传功能,insertIntoDatabase,在没有任何芹菜参与的情况下工作正常,但现在上传不起作用。事实上,当我尝试上传时,我的网站很快告诉我上传成功了,但实际上什么也没有上传 服务器由docker compose up启动,它将进行迁移、执行迁移、收集静态文件、更新要求,然后启动服务器。这一切都是通过使

在过去的一周里,我一直在尝试学习芹菜,并将其添加到使用Django和Docker Compose的项目中。我很难理解如何让它工作;我的问题是,在使用任务时,我似乎无法上传到我的数据库来工作。上传功能,
insertIntoDatabase
,在没有任何芹菜参与的情况下工作正常,但现在上传不起作用。事实上,当我尝试上传时,我的网站很快告诉我上传成功了,但实际上什么也没有上传

服务器由
docker compose up
启动,它将进行迁移、执行迁移、收集静态文件、更新要求,然后启动服务器。这一切都是通过使用
路面.py
完成的;Dockerfile中的命令是
CMD paver docker\u run
。在任何情况下,芹菜工人都不是明确开始工作的;我应该这么做吗?如果是,怎么做

这就是我在
views.py中调用上载函数的方式:

insertIntoDatabase.delay(datapoints, user, description)
class DBTask(Task):
     abstract = True

     def on_failure(self, exc, *args, **kwargs):
        raise exc
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"
上载函数在名为
databaseinserter.py
的文件中定义。以下装饰程序用于插入数据库

@shared_task(bind=True, name="database_insert", base=DBTask)
下面是
芹菜.py
DBTask
类的定义:

insertIntoDatabase.delay(datapoints, user, description)
class DBTask(Task):
     abstract = True

     def on_failure(self, exc, *args, **kwargs):
        raise exc
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"
我真的不确定要为
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):
下面是我用来配置芹菜的设置(
settings.py
):


现在,我猜
tasks.py中的
database\u insert
不应该是空的,但是应该放什么呢?而且,
tasks.py
中似乎没有发生任何事情——当我添加一些日志语句以查看
tasks.py
是否至少正在运行时,实际上没有任何内容被记录下来,这让我觉得
tasks.py
甚至没有运行。如何正确地将上载功能设置为任务

我想你离这项工作还不远

首先,我建议您尝试将芹菜任务和业务逻辑分开。因此,例如,在
insertIntoDatabase
函数中将数据插入数据库,然后分别创建一个芹菜任务(可能名为
insert\u into\u DB\u task
),该任务将args作为普通python对象接收进来,这可能很有意义(重要)并使用这些参数调用前面提到的
insertIntoDatabase
函数,以实际完成DB插入

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

my_应用程序/任务/将_插入_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)
我的应用程序/services/insertIntoDatabase.py

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

    # do db insertion stuff
我的应用程序/视图/插入视图.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),调整任务失败时会发生什么(稍后重试?中止任务?等等),记录日志,否则他们会执行其他地方的业务逻辑


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

您传递给delay()的数据点和用户参数是什么?
datapoints
是字典对象的列表,
user
只是一个字符串。数据点被转换成适合我们的
models.py
的Django对象。在引入芹菜之前,上传一直运作良好。这似乎是一个很好的方式。我有几个问题:1。当你提到我的_应用程序时,你是说它与我的_项目不同,对吗?我的
insertIntoDatabase
myu项目/utils/db
中,而不是在myu应用程序中;这不应该是个问题,对吧?2.你对如何在docker compose的背景下开始一个芹菜工人有什么想法吗?正如您可以想象的那样,正常的CLI方法不起作用
roadway.py
似乎也无法识别芹菜。无论如何,谢谢你帮助我更好地理解芹菜!事实上,我想我找到了一种方法,通过使用启动芹菜工人的命令制作另一个容器。我遇到了一些问题,但这是一系列新的问题。您的示例代码实际上帮助我解决了与此问题相关的问题,因此我将此标记为答案。1。虽然让你的应用程序依赖于你的项目会降低你的应用程序的独立性和可移植性,但这应该没问题。建筑权衡。宾果-启动第二个容器来运行芹菜,使用与Web容器相同的一般设置思想。如果您使用django celery,您可以使用与Web容器相同的docker映像,并将命令更改为类似于
manage.py celeryd
,而不是使用uwsgi、gunicorn、runserver等。这就是我运行开发环境的方式:我使用1个docker映像来运行3个单独的容器。Web容器
manage.py运行服务器0.0.0.0:8000
、芹菜容器
manage.py芹菜ID
、芹菜节拍容器
manage.py芹菜节拍