web-dev-qa-db-ja.com

add_periodic_taskを使用して動的にCelery(celerybeat)に定期的なタスクを設定する

Celery 4.0.1Django 1.10とともに使用していますが、タスクのスケジュールに問題があります(タスクの実行は正常に機能します)。これはセロリの設定です:

os.environ.setdefault('Django_SETTINGS_MODULE', 'myapp.settings')
app = Celery('myapp')

app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

app.conf.BROKER_URL = 'amqp://{}:{}@{}'.format(settings.AMQP_USER, settings.AMQP_PASSWORD, settings.AMQP_Host)
app.conf.CELERY_DEFAULT_EXCHANGE = 'myapp.celery'
app.conf.CELERY_DEFAULT_QUEUE = 'myapp.celery_default'
app.conf.CELERY_TASK_SERIALIZER = 'json'
app.conf.CELERY_ACCEPT_CONTENT = ['json']
app.conf.CELERY_IGNORE_RESULT = True
app.conf.CELERY_DISABLE_RATE_LIMITS = True
app.conf.BROKER_POOL_LIMIT = 2

app.conf.CELERY_QUEUES = (
    Queue('myapp.celery_default'),
    Queue('myapp.queue1'),
    Queue('myapp.queue2'),
    Queue('myapp.queue3'),
)

次に、tasks.pyで次のようにします。

@app.task(queue='myapp.queue1')
def my_task(some_id):
    print("Doing something with", some_id)

Views.pyで、このタスクをスケジュールします。

def my_view(request, id):
    app.add_periodic_task(10, my_task.s(id))

次に、コマンドを実行します。

Sudo systemctl start rabbitmq.service
celery -A myapp.celery_app beat -l debug
celery worker -A myapp.celery_app

ただし、タスクがスケジュールされることはありません。ログに何も表示されません。タスクが機能しているのは、私の見解では、

def my_view(request, id):
    my_task.delay(id)

タスクが実行されます。

私の構成ファイルにある場合、このようにタスクを手動でスケジュールすると、それは機能します:

app.conf.CELERYBEAT_SCHEDULE = {
    'add-every-30-seconds': {
        'task': 'tasks.my_task',
        'schedule': 10.0,
        'args': (66,)
    },
}

タスクを動的にスケジュールすることはできません。何か案が?

9
Marc

編集:(2018年1月13日)

最新の リリース4.1. がこの件名に対処しました ticket#3958 とマージされました


ビートスケジュール設定が最初に読み込まれ、実行時に再スケジュールできないため、実際にはビューレベルで定期的なタスクを定義することはできません。

add_periodic_task() 関数は、裏でbeat_schedule設定にエントリを追加します。同じ設定を使用して、定期的なタスクを手動で設定することもできます。

_app.conf.CELERYBEAT_SCHEDULE = {
    'add-every-30-seconds': {
        'task': 'tasks.my_task',
        'schedule': 10.0,
        'args': (66,)
    },
}
_

つまり、add_periodic_task()を使用する場合は、セロリアプリレベルで_on_after_configure_ハンドラー内にラップする必要があり、実行時の変更は有効になりません。

_app = Celery()

@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
    sender.add_periodic_task(10, my_task.s(66))
_

doc で述べたように、通常のcelerybeatはタスクの実行を追跡するだけです。

デフォルトのスケジューラーは _celery.beat.PersistentScheduler_ で、ローカルのシェルブデータベースファイルで最後の実行時間を追跡するだけです。

定期的にタスクを動的に管理し、実行時にcelerybeatを再スケジュールできるようにするには、次のようにします。

Djangoデータベースにスケジュールを保存し、便利な管理インターフェイスを提供する Django-celery-beat 拡張機能もあります。実行時に定期的なタスクを管理します

タスクはDjangoデータベースに永続化され、スケジューラはタスクモデルでdbレベルで更新できます。定期的なタスクを更新するたびに、このタスクテーブルのカウンターがインクリメントされ、データベースからスケジュールをリロードするためのセロリビートサービス。

あなたのための可能な解決策は次のようになります:

_from Django_celery_beat.models import PeriodicTask, IntervalSchedule

schedule= IntervalSchedule.objects.create(every=10, period=IntervalSchedule.SECONDS)
task = PeriodicTask.objects.create(interval=schedule, name='any name', task='tasks.my_task', args=json.dumps([66]))
_

views.py

_def update_task_view(request, id)
    task = PeriodicTask.objects.get(name="task name") # if we suppose names are unique
    task.args=json.dumps([id])
    task.save()
_
20
DhiaTN