【问题标题】:Django celery trigger manage.py cmd @periodic_taskDjango celery 触发器 manage.py cmd @periodic_task
【发布时间】:2019-06-11 03:40:23
【问题描述】:

我想每隔 x 分钟从 celery 运行一个 manage.py cmd 作为定期任务,但每次我尝试完成如下所示的操作时,我都会收到以下错误:

[2019-01-17 01:36:00,006: INFO/MainProcess] 收到的任务:删除 未使用的媒体文件[3dd2b93b-e32a-4736-8b24-028b9ad8da35]
[2019-01-17 01:36:00,007:警告/ForkPoolWorker-3] 正在扫描 未使用的媒体文件 [2019-01-17 01:36:00,008: WARNING/ForkPoolWorker-3] 未知命令:'cleanup_unused_media --noinput --remove-empty-dirs' [2019-01-17 01:36:00,008:INFO/ForkPoolWorker-3] 任务删除未使用 媒体文件[3dd2b93b-e32a-4736-8b24-028b9ad8da35] 成功 0.0008139749998008483s:无

tasks.py

from celery import Celery
from celery.schedules import crontab
from celery.task import periodic_task
from celery.utils.log import get_task_logger
import requests
from django.core import management


logger = get_task_logger(__name__)
app = Celery('tasks', broker='redis://127.0.0.1')

...
@periodic_task(run_every=(crontab(minute='*/90')), name="Delete unused media file(s)", ignore_result=True)
def delete_unused_media():
    try:
        print("Scanning for unused media files")
        management.call_command('cleanup_unused_media --noinput --remove-empty-dirs')
        return "success, old media files have been deleted"
    except Exception as e:
        print(e)

该管理 cmd 来自以下项目: https://github.com/akolpakov/django-unused-media

我的管理层电话是完全错误的还是怎么回事?

提前致谢

更新(Celery 配置):

settings.py

INSTALLED_APPS = [
...
'celery',
'django_unused_media',
...
# Celery Settings:
BROKER_URL = 'redis://127.0.0.1:6379'
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'UTC'
...
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": [
            "redis://127.0.0.1:6379/0",
            #"redis://127.0.0.1:6379/1",
        ],
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "SOCKET_CONNECT_TIMEOUT": 15,  # in seconds
            "SOCKET_TIMEOUT": 15,  # in seconds
            "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor",
            "CONNECTION_POOL_KWARGS": {"max_connections": 1000, "retry_on_timeout": True}
        }
    }
}

芹菜.py

from __future__ import absolute_import, unicode_literals
from celery import Celery
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyProject.settings')

app = Celery('MyProject')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()



@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))

_init__.py

from __future__ import absolute_import, unicode_literals

# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app

__all__ = ('celery_app')

例如此任务运行良好:

@periodic_task(run_every=(crontab(minute='*/1')), name="Get exchange rate(s)", ignore_result=True)
def get_exchange_rate():
    api_url = "https://api.coinmarketcap.com/v1/ticker/?limit=1"
    try:
        exchange_rate = requests.get(api_url).json()
        logger.info("BTC Exchange rate updated successfully.")
    except Exception as e:
        print(e)
        exchange_rate = dict()
    return exchange_rate

【问题讨论】:

  • 能否从命令行手动运行管理命令?
  • 是的,这就像一个魅力;)我不知道为什么它不应该在这里工作。

标签: python django triggers celery manage.py


【解决方案1】:

对于任何使用 Django 1.7+ 的人来说,似乎仅仅导入设置模块是不够的。

我是这样工作的

from celery import Celery
from celery.schedules import crontab
from celery.task import periodic_task
from celery.utils.log import get_task_logger
import requests, os, django
from django.core import management


logger = get_task_logger(__name__)
app = Celery('tasks', broker='redis://127.0.0.1')

@periodic_task(run_every=(crontab(minute='*/1')), name="Delete unused media file(s)", ignore_result=True)
def delete_unused_media():
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MyProject.settings")
    django.setup()
    try:
        print("Scanning for unused media files")
        management.call_command('cleanup_unused_media', '--noinput', '--remove-empty-dirs')
        return "success, old media files have been deleted"
    except Exception as e:
        print(e)

【讨论】:

    【解决方案2】:

    问题在于您调用call_command 的方式。 call_command 将命令的名称作为其第一个参数,然后是按位置传递的参数。您将整个批次作为单个字符串传递。尝试将其更改为:

    management.call_command('cleanup_unused_media', '--noinput', '--remove-empty-dirs')
    

    【讨论】:

    • 遗憾的是仍然无法正常工作:( ** 收到的任务:删除未使用的媒体文件 [96e6c763-7086-4b63-b988-d5dbf8ed5817] [2019-01-17 18:00:00,100: 警告/ForkPoolWorker-4] 扫描未使用的媒体文件 [2019-01-17 18:00:00,102:警告/ForkPoolWorker-4] 未知命令:'cleanup_unused_media' [2019-01-17 18:00:00,103:INFO/ForkPoolWorker- 4]任务删除未使用的媒体文件[96e6c763-7086-4b63-b988-d5dbf8ed5817]在0.0029836410030839033s成功:无**
    • 但似乎我的所有命令都有这个问题,我实际上什至无法触发 syncdb 或 makemigration。知道我忘记了什么
    • Django 尝试通过在INSTALLED_APPS 中的每个已安装应用程序中查找管理命令来发现它们。你能展示一下 Celery 是如何配置/启动的吗?
    • 我刚刚添加了这些行。提前致谢
    • 你是如何启动工作进程的?使用celery worker 命令,还是使用celeryd 等?
    猜你喜欢
    • 2013-07-13
    • 2014-01-17
    • 2019-04-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2019-08-03
    相关资源
    最近更新 更多