Celery: add_periodic_task ํ•จ์ˆ˜๊ฐ€ ์ž‘์—…์„ ํŠธ๋ฆฌ๊ฑฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2016๋…„ 11์›” 13์ผ  ยท  33์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: celery/celery

์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • [x] ๋ฌธ์ œ์— celery -A proj report ์˜ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ–ˆ์Šต๋‹ˆ๋‹ค.
    (๋‹น์‹ ์ด ์ด๊ฒƒ์„ ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด, ์ ์–ด๋„ ์…€๋Ÿฌ๋ฆฌ๋ฅผ ์ง€์ •ํ•˜์‹ญ์‹œ์˜ค
    ์˜ํ–ฅ์„๋ฐ›๋Š” ๋ฒ„์ „).
  • [x] Celery์˜ master ์ง€์ ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

์žฌํ˜„ ๋‹จ๊ณ„

tasks.py

from celery import Celery

celery = Celery('tasks', broker='pyamqp://guest@localhost//')

@celery.task
def add(x, y):
    return x + y


@celery.on_after_configure.connect
def add_periodic():
    celery.add_periodic_task(10.0, add.s(2,3), name='add every 10')

if __name__ == '__main__':
        add_periodic()


1 ๋‹จ๊ณ„ : rabbitmq ์‹คํ–‰
rabbitmq 1186 1 0 Nov12? 00:00:00 / bin / sh / usr / sbin / rabbitmq-server

2 ๋‹จ๊ณ„ : tasks.py ์‹คํ–‰
python tasks.py
step3 : ๋น„ํŠธ ์ž‘์—…์ž ์‹œ์ž‘
celery -A tasks -l info beat
์…€๋Ÿฌ๋ฆฌ ๋น„ํŠธ v4.0.0 (latentcall)์ด ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.
__-... __-_
ํ˜„์ง€ ์‹œ๊ฐ„-> 2016-11-12 17:37:58
๊ตฌ์„ฑ->
. ๋ธŒ๋กœ์ปค-> amqp : // guest : ** @localhost : 5672 //
. ๋กœ๋”-> celery.loaders.app.AppLoader
. ์Šค์ผ€์ค„๋Ÿฌ-> celery.beat.PersistentScheduler
. db-> celerybeat-schedule
. ๋กœ๊ทธ ํŒŒ์ผ-> [stderr] @ % INFO
. maxinterval-> 5.00 ๋ถ„ (300 ์ดˆ)
[2016-11-12 17 : 37 : 58,912 : INFO / MainProcess] beat : ์‹œ์ž‘ ์ค‘ ...

์˜ˆ์ƒ๋˜๋Š” ํ–‰๋™

์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ 10 ์ดˆ๋งˆ๋‹ค add () ํ•จ์ˆ˜๋ฅผ ํŠธ๋ฆฌ๊ฑฐ ํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ํ–‰๋™

add () ํ•จ์ˆ˜๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
ํ„ฐ๋ฏธ๋„์— ์˜ˆ์™ธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋†“์นœ ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

Celerybeat Bug Report

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ฃผ๊ธฐ์ ์ธ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด -B ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…์ž๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ ์Šค์ผ€์ค„๋Ÿฌ๋„ ํ˜ธ์ถœํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

celery -A proj worker -B

์ž‘์—…์ด ์• ํ”Œ ๋ฆฌ์ผ€์ด์…˜์—์„œ autodiscoveredํ•˜๋Š” ์žฅ๊ณ  ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ์…€๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ๋‹น์‹ ์€ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ on_after_finalize ๋Œ€์‹ ์— ์‹ ํ˜ธ on_after_configure .

์ฐธ๊ณ  ๋ฌธํ—Œ :
http://stackoverflow.com/questions/40712678/setup-periodic-task/40727526
http://stackoverflow.com/questions/41119053/connect-new-celery-periodic-task-in-django

๋ชจ๋“  33 ๋Œ“๊ธ€

๋‚˜๋Š” ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค :(

๊ท€ํ•˜์˜ ๋ชจ๋ฒ”์€ ์ €์—๊ฒŒ ์ž˜ ๋งž์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  : ์‹ ํ˜ธ ์ฒ˜๋ฆฌ๊ธฐ๋Š” ** kwargs๋ฅผ ์ˆ˜๋ฝํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒํ•˜์ง€ ์•Š์œผ๋ฉด ํ–ฅํ›„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‹น์‹ ์˜ ์˜ˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ

# file: tasks.py
from celery import Celery

celery = Celery('tasks', broker='pyamqp://guest@localhost//')

@celery.task
def add(x, y):
    return x + y


@celery.on_after_configure.connect
def add_periodic(**kwargs):
    celery.add_periodic_task(10.0, add.s(2,3), name='add every 10')

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋น„ํŠธ ์„œ๋น„์Šค๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

$ celery -A tasks beat -l debug
celery beat v4.0.0 (latentcall) is starting.
__    -    ... __   -        _
LocalTime -> 2016-12-01 11:54:56
Configuration ->
    . broker -> amqp://guest:**<strong i="11">@localhost</strong>:5672//
    . loader -> celery.loaders.app.AppLoader
    . scheduler -> celery.beat.PersistentScheduler
    . db -> celerybeat-schedule
    . logfile -> [stderr]@%DEBUG
    . maxinterval -> 5.00 minutes (300s)
[2016-12-01 11:54:56,511: DEBUG/MainProcess] Setting default socket timeout to 30
[2016-12-01 11:54:56,511: INFO/MainProcess] beat: Starting...
[2016-12-01 11:54:56,517: DEBUG/MainProcess] Current schedule:
<ScheduleEntry: celery.backend_cleanup celery.backend_cleanup() <crontab: 0 4 * * * (m/h/d/dM/MY)>
<ScheduleEntry: add every 10 tasks.add(2, 3) <freq: 10.00 seconds>
[2016-12-01 11:54:56,517: DEBUG/MainProcess] beat: Ticking with max interval->5.00 minutes
[2016-12-01 11:54:56,528: DEBUG/MainProcess] Start from server, version: 0.9, properties: {'information': 'Licensed under the MPL.  See http://www.rabbitmq.com/', 'product': 'RabbitMQ', 'copyright': 'Copyright (C) 2007-2016 Pivotal Software, Inc.', 'capabilities': {'exchange_exchange_bindings': True, 'connection.blocked': True, 'authentication_failure_close': True, 'direct_reply_to': True, 'basic.nack': True, 'per_consumer_qos': True, 'consumer_priorities': True, 'consumer_cancel_notify': True, 'publisher_confirms': True}, 'cluster_name': 'rabbit<strong i="12">@grain</strong>', 'platform': 'Erlang/OTP', 'version': '3.6.4'}, mechanisms: [u'AMQPLAIN', u'PLAIN'], locales: [u'en_US']
[2016-12-01 11:54:56,531: INFO/MainProcess] Scheduler: Sending due task add every 10 (tasks.add)
[2016-12-01 11:54:56,534: DEBUG/MainProcess] using channel_id: 1
[2016-12-01 11:54:56,535: DEBUG/MainProcess] Channel open
[2016-12-01 11:54:56,537: DEBUG/MainProcess] beat: Synchronizing schedule...
[2016-12-01 11:54:56,537: DEBUG/MainProcess] tasks.add sent. id->af224838-cf72-4d0d-9076-1c39cdbeffb8
[2016-12-01 11:54:56,537: DEBUG/MainProcess] beat: Waking up in 9.97 seconds.
[2016-12-01 11:55:06,519: INFO/MainProcess] Scheduler: Sending due task add every 10 (tasks.add)
[2016-12-01 11:55:06,520: DEBUG/MainProcess] tasks.add sent. id->907cf307-e36f-455a-97a8-441c79b8ab92

์•ˆ๋…•ํ•˜์„ธ์š”, ์ €๋„ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ €๋Š” ์Šค๋ ˆ๋“œ์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์…€๋Ÿฌ๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค. ์›์ธ ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚ด ์Šค๋ ˆ๋“œ์ž…๋‹ˆ๋‹ค.

from __future__ import absolute_import, unicode_literals
import threading
from celery import current_app
from celery.bin import worker

app = current_app._get_current_object()


class CeleryThread(threading.Thread):
    def __init__(self):
        super(CeleryThread, self).__init__()

        self.app = app
        self.worker = worker.worker(app=self.app)

        self.options = {
            'broker': 'amqp://guest:guest<strong i="7">@localhost</strong>:5672//',
            'loglevel': 'INFO',
            'traceback': True,
        }

        app.add_periodic_task(5.0, test.s('hello'), name='add every 10')

    def run(self):
        self.worker.run(**self.options)


@app.task
def test(args1):
    print args1

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์„ ์‹œ์ž‘ํ•˜๋Š” main.py

celery_thread = CeleryThread()
# used to kill the thread when the main program stop
# celery_thread.daemon = True
celery_thread.start()

๋‚ด ์ฝ˜์†” ์ถœ๋ ฅ์€

 -------------- celery<strong i="14">@ubuntu</strong> v4.0.0 (latentcall)
---- **** ----- 
--- * ***  * -- Linux-4.4.0-51-generic-x86_64-with-Ubuntu-16.04-xenial 2016-12-03 14:33:10
-- * - **** --- 
- ** ---------- [config]
- ** ---------- .> app:         default:0x7f75775bfc50 (.default.Loader)
- ** ---------- .> transport:   amqp://guest:**<strong i="15">@localhost</strong>:5672//
- ** ---------- .> results:     disabled://
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery


[tasks]
  . kalliope.core.CrontabManager2.CeleryThread.test

[2016-12-03 14:33:10,458: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2016-12-03 14:33:10,466: INFO/MainProcess] mingle: searching for neighbors
[2016-12-03 14:33:11,486: INFO/MainProcess] mingle: all alone
[2016-12-03 14:33:11,515: INFO/MainProcess] celery<strong i="16">@ubuntu</strong> ready.

์˜ต์…˜์„ ์žŠ์—ˆ์Šต๋‹ˆ๊นŒ? @ask ์ถœ๋ ฅ์— "scheduler"๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„์›€์„ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

@ liuallen1981 ๊ณผ ๋™์ผํ•œ ๊ตฌ์„ฑ ๋ฐ ๋™์ผํ•œ ๋ฌธ์ œ. ๋ˆ„๊ตฌ๋‚˜ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ์•„๋ƒ…๋‹ˆ๋‹ค. ์ง€๊ธˆ์€

celery.conf.beat_schedule = {
    'do-something-periodically': {
        'task': 'tasks.my_task',
        'schedule': 3.0,
    },
}

on_after_configure.connect ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ํ•จ๊ป˜ setup_periodic_tasks ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ .

+1์ด ๋ฌธ์ œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

+1์ด ๋ฌธ์ œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
Celery ๋ฒ„์ „ 4.0.2 (latentcall)

+1์ด ๋ฌธ์ œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

+1์ด ๋ฌธ์ œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. @ liuallen1981 ์˜ ์ฝ”๋“œ๋กœ ํ…Œ์ŠคํŠธํ•˜๊ณ  ํ…Œ์ŠคํŠธํ–ˆ์œผ๋ฉฐ ๋‚ด ์ฝ”๋“œ์™€ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.

์…€๋Ÿฌ๋ฆฌ : 4.0.2

์ฃผ๊ธฐ์ ์ธ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด -B ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…์ž๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ ์Šค์ผ€์ค„๋Ÿฌ๋„ ํ˜ธ์ถœํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

celery -A proj worker -B

์ž‘์—…์ด ์• ํ”Œ ๋ฆฌ์ผ€์ด์…˜์—์„œ autodiscoveredํ•˜๋Š” ์žฅ๊ณ  ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ์…€๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ๋‹น์‹ ์€ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ on_after_finalize ๋Œ€์‹ ์— ์‹ ํ˜ธ on_after_configure .

์ฐธ๊ณ  ๋ฌธํ—Œ :
http://stackoverflow.com/questions/40712678/setup-periodic-task/40727526
http://stackoverflow.com/questions/41119053/connect-new-celery-periodic-task-in-django

-B๋Š” ํ”„๋กœ๋•์…˜ ์šฉ์ด ์•„๋‹ˆ๋ฉฐ ์ ์–ด๋„ ์ œ ๊ฒฝ์šฐ์—๋Š” ์ด๋ฏธ ์‹คํ–‰์ค‘์ธ Beats ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

+1 Celery (4.0.2)์™€ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ

์—ฌ๊ธฐ์— ๊ฐ™์€ ๋ฌธ์ œ ....

๋น„ํŠธ ์„œ๋น„์Šค๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ๋งŒํ•˜๋ฉด ์ž‘์—…์„ ์ˆ˜ํ–‰ ํ•  ์ž‘์—…์ž๋„ ์‹œ์ž‘ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

+1

์—ฌ๊ธฐ์— ๊ฐ™์€ ๋ฌธ์ œ

์—ฌ๊ธฐ์— ๊ฐ™์€ ๋ฌธ์ œ,

์ฝœ๋ฐฑ ๋‚ด๋ถ€์— ๋ฌด์–ธ๊ฐ€๋ฅผ ์ธ์‡„ํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ๋Š”๋ฐ ์ฝœ๋ฐฑ์ด ํ˜ธ์ถœ๋˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์ง€๋งŒ RabbitMQ๊ฐ€ ์ž‘๋™ ์ค‘์ž…๋‹ˆ๋‹ค (์ฝ”๋“œ์—์„œ ์ž‘์—…์„ ํŠธ๋ฆฌ๊ฑฐ ํ•  ๋•Œ ์ œ๋Œ€๋กœ ์ž‘๋™ ํ•จ).

@celery.on_after_configure.connect
def setup_periodic_tasks(**kwargs):
    print('after connect')
(py35) โžœ  celery -A celery.beat beat
celery beat v4.0.2 (latentcall) is starting.
__    -    ... __   -        _
LocalTime -> 2017-08-08 02:42:18
Configuration ->
    . broker -> amqp://**:**@**:5672//
    . loader -> celery.loaders.app.AppLoader
    . scheduler -> celery.beat.PersistentScheduler
    . db -> celerybeat-schedule
    . logfile -> [stderr]@%WARNING
    . maxinterval -> 5.00 minutes (300s)

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋™์ ์œผ๋กœ add_periodic_task celery.conf.beat_schedule ๋Œ€์‹  Celery ๊ตฌ์„ฑ

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ดํŽด ๋ณด๋‹ˆ on_after_configure ์‹œ๊ทธ๋„์ด ๋ฐœ์ƒํ•œ ํ›„ ์‹œ๊ทธ๋„ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ƒ์„ฑ / ์—ฐ๊ฒฐ๋˜๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. (๋‚ด ์‹ ํ˜ธ ๋ฆฌ์Šค๋„ˆ๋ฅผ app/tasks.py ์— ๋ฐฐ์น˜ํ–ˆ๋Š”๋ฐ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.)

Django์˜ ์•ฑ ์ค€๋น„ ์‹ ํ˜ธ๋Š” ์•„๋งˆ๋„ Celery ๊ตฌ์„ฑ ํ›„์— ์‹คํ–‰๋  ๊ฒƒ์ด๋ฉฐ ์ง€๊ธˆ๊นŒ์ง€ ์ž˜ ์ž‘๋™ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  : ์‹ค์ œ๋กœ ์…€๋Ÿฌ๋ฆฌ ๊ตฌ์„ฑ์ด ์–ด๋–ค ๊ฒƒ์ธ์ง€, ๊ทธ๋ฆฌ๊ณ  ์…€๋Ÿฌ๋ฆฌ๊ฐ€ ๊ตฌ์„ฑ๋˜๊ธฐ ์ „์— app.ready๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ์ ์–ด๋„ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‚ด app/apps.py ์ƒ˜ํ”Œ ์ฝ”๋“œ :

from django.apps import AppConfig
import django.db.utils
from celery_app import app as celery_app
from celery.schedules import crontab
import utils.cron


class MyAppConfig(AppConfig):
    name = 'app'
    verbose_name = "MyApp"

    def ready(self):
        print("MyAppConfig.ready invoked.")
        import app.signals

        print("* * * Setting up periodic tasks!")
        import app.models
        import app.tasks
        for cron in app.models.CronTask.objects.all():
            celery_app.add_periodic_task(
                crontab(**utils.cron.parse_crontab_expression_to_celery(cron.frequency)),
                app.tasks.do_cron.s(cron.id),
                name='do cron'
            )

๋‹น์‹ ์€ ๋˜ํ•œ ์ง€์  ํ•  ํ•„์š”๊ฐ€ ์ฐธ๊ณ  INSTALLED_APPS ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ AppConfig ์—์„œ settings.py :

INSTALLED_APPS = [
    # ...
    'app.apps.MyAppConfig',
]

์ข‹์€ ์ ‘๊ทผ๋ฒ•์ด๋‚˜ ์ˆ˜์ • ์€ ์•„๋งˆ๋„ 1) Celery๊ฐ€ ์ด๋ฏธ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์ฆ‰์‹œ ์‹คํ–‰๋˜๊ณ  2) Celery๊ฐ€ ๊ตฌ์„ฑ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ @celery.on_after_configure.connect ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ƒˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ ์ค‘ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด์ด ๋ฌธ์ œ์— ๋ถ€๋”ช ํ˜”๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์„œ๋Š” ๋ฌธ์ œ๊ฐ€๋ฉ๋‹ˆ๋‹ค.

@rustanacexd @viennadd๋ฅผ ์ฐธ์กฐ ํ•˜์—ฌ ์ž‘์—…์„ ๋™์ ์œผ๋กœ ์˜ˆ์•ฝํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ์ด ์ˆ˜์ •์„ ์‹œ๋„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

2 ์„ผํŠธ๋ฅผ ๋‚ด๋†“๊ณ , ๋‚˜๋Š” ์ด๊ฒƒ์— ์กฐ๊ธˆ์”ฉ ๋น ์ ธ์„œ ๋‚ด ์ž‘์—…์˜ ์ผ๋ถ€๋ฅผ ์žฌ์ •๋ ฌํ•ด์•ผํ–ˆ๋‹ค. ์‹คํ–‰๋  ์˜ˆ์ •์ธ ์ž‘์—…์ด ์•ฝ 8 ๊ฐœ ์žˆ์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค.

์˜ˆ:

@celery.on_after_configure.connect
def setup_periodic_tasks(**kwargs):
    celery.add_periodic_task(5.0, do_thing_b.s(), name='Test B')
    celery.add_periodic_task(4.9, do_thing_a.s(), name='Test A')

์ด๋ ‡๊ฒŒ ์ฃผ๋ฌธํ•˜๋ฉด do_thing_a ๋Š” do_thing_b ๋กœ ๋ฎ์–ด ์“ฐ์—ฌ ์ง€๋ฏ€๋กœ ์ ˆ๋Œ€ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์›๋ž˜ ๋‘˜ ๋‹ค 5 ๋กœ ์„ค์ •๋˜์—ˆ์ง€๋งŒ ํ•˜๋‚˜๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค (์ด ๊ฒฝ์šฐ ๋จผ์ € ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฏ€๋กœ B ์˜€์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค). ๋‹ค์Œ์œผ๋กœ 10 ์ง„์ˆ˜๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  .1 ๋กœ ์˜คํ”„์…‹ํ•˜์—ฌ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜๋Š”์ง€ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์‚ฌ์œ„๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‚˜๋Š” ๋‚ฎ์€ ์ชฝ์ด ๋จผ์ € ๋ฐœ์‚ฌ๋˜๊ณ  ๋†’์€ ์ชฝ์ด ๋‘ ๋ฒˆ์งธ๋กœ ๋ฐœ์‚ฌ๋˜๋„๋ก ๋ช…๋ นํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰ :

@celery.on_after_configure.connect
def setup_periodic_tasks(**kwargs):
    celery.add_periodic_task(4.9, do_thing_b.s(), name='Test B')
    celery.add_periodic_task(5.0, do_thing_a.s(), name='Test A')

์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ์•ฝ๊ฐ„์˜ crontab() ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€๋งŒ, ๊ทธ๊ฒƒ๋“ค์€ ์–ด๋–ค ์ž‘์—…์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์€ ์ผ์ข…์˜ ๋ฏธ์Šคํ…Œ๋ฆฌ์ด์ง€๋งŒ, ์–ด๋–ค ๊ฒƒ์€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐ„๊ฒฉ์€ ์ผ๋ฐ˜์ ์œผ๋กœ X ์‹œ๊ฐ„ / ์ผ๋งˆ๋‹ค ๋ฐœ์ƒํ•˜๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์™„์ „ํžˆ ๋†€์•„ ๋ณด์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์•„๋งˆ๋„ ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ํ–‰๋™์ด ๋ฌธ์„œ์— ์–ธ๊ธ‰๋˜์–ด ์žˆ๊ฑฐ๋‚˜,์ด ํ–‰๋™์ด ๊ทธ๋‹ค์ง€ ๋ง์ด๋˜์ง€๋Š” ์•Š์ง€๋งŒ ๋‹ค๋ฅธ ํ† ๋ผ ๊ตด๋กœ ๋‚ด๋ ค๊ฐˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ RMQ ๋ฐ celery 4.1.0 ๋Œ€์‹  Redis๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š”์ด ์ผ์„ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ๋‚ด ๋Œ€๋‹ต์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

https://stackoverflow.com/a/46965132/560945

@ prasanna-balaraman ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ œ์•ˆ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‚˜์—๊ฒŒ ๊ฐ™์€ ๋ฌธ์ œ : ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์„ ํ…Œ์ŠคํŠธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค : https://stackoverflow.com/a/41119054/6149867

ํ์‡„. ์—ฌ์ „ํžˆ ๋‚˜ํƒ€๋‚˜๊ณ  ๋ˆ„๊ตฐ๊ฐ€ ์ฝ”๋“œ ๋˜๋Š” ๋ฌธ์„œ ์ œ์•ˆ์ด ์žˆ์œผ๋ฉด์ด ๋ฌธ์ œ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ™๋ณด ์ž๋ฃŒ๋ฅผ ๋ณด๋‚ด ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

setup_periodic_tasks์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์กฐ์šฉํžˆ ์–ต์ œ๋œ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋Š” ์—ฌ๊ธฐ์—์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค : https://github.com/celery/celery/blob/master/celery/app/base.py#L950

๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์˜ˆ์™ธ๋Š” ์‘๋‹ต์—๋งŒ ์ €์žฅ๋˜๊ณ  ์žฌ๋ฐœ์ƒ์ด๋‚˜ ๊ธฐ๋ก์€ ์—†์Šต๋‹ˆ๋‹ค.
https://github.com/celery/celery/blob/master/celery/utils/dispatch/signal.py#L276

๊ทธ๋ž˜์„œ ์ œ ์ œ์•ˆ์€ setup_periodic_tasks๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค!

@ chiang831 ๊ฐœ์„ ์— ๋Œ€ํ•œ ์ œ์•ˆ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ ‡๋‹ค๋ฉด plz๋Š” ํ™๋ณด๋ฅผ ๋ณด๋‚ด๊ฑฐ๋‚˜ ์…€๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์ž ๋ฉ”์ผ ๋ง๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•œ ํ† ๋ก ์„ ์—ฝ๋‹ˆ ๋‹ค.

on_after_finalize ์—์„œ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค (๋น„ ์žฅ๊ณ  ์…€๋Ÿฌ๋ฆฌ ์•ฑ).

@app.on_after_finalize.connect
def app_ready(**kwargs):
    """
    Called once after app has been finalized.
    """
    sender = kwargs.get('sender')

    # periodic tasks
    speed = 15
    sender.add_periodic_task(speed, update_leases.s(),
        name='update leases every {} seconds'.format(speed))

๋ฐฉ๊ธˆ ์ด๊ฒƒ์— ๋ถ€๋”ช ์ณค๊ณ  ์ด์ „ ์†”๋ฃจ์…˜ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ผ์œผํ‚ค๋Š” ์ •ํ™•ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ํ˜ผ๋ž€์Šค๋Ÿฝ๊ณ  ref-counting / gc์˜ ๋™์ž‘๊ณผ ๋ฐ์ฝ” ๋ ˆ์ดํŒ… ๋œ ํ•จ์ˆ˜์˜ ์ •ํ™•ํ•œ ์ˆ˜๋ช…์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ Signal.connect๋Š” ์‹ ํ˜ธ ์ฒ˜๋ฆฌ๊ธฐ์— ๋Œ€ํ•œ ์•ฝํ•œ ์ฐธ์กฐ ๋งŒ ๋ณด์œ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Signal ๊ฐ์ฒด (์‹ ํ˜ธ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๋‹จ๋ช… ๊ฐ์ฒด)์˜ ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ ํ•ฉํ•˜์ง€๋งŒ์ด ๊ฒฝ์šฐ์—๋Š” ๋งค์šฐ ๋†€๋ž์Šต๋‹ˆ๋‹ค.

๋‚ด ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์ƒˆ๋กœ์šด ์ฃผ๊ธฐ์  ์ž‘์—…์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ ํ•  ์ˆ˜์žˆ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜€์Šต๋‹ˆ๋‹ค.

def call_every_5_min(task):
    @app.on_after_configure.connect
    def register_task(sender, **_):
        sender.add_periodic_task(collect_every_m*60, task.signature())

<strong i="8">@call_every_5_min</strong>
<strong i="9">@task</strong>
def my_celery_task(_):
     pass

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋ช…์‹œ ์ ์œผ๋กœ ๊ฐ•๋ ฅํ•œ ์ฐธ์กฐ๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

def call_every_5_min(task):
    def register_task(sender, **_):
        sender.add_periodic_task(collect_every_m*60, task.signature())
    app.on_after_configure.connect(register_task, weak=False)

๋ฌธ์„œ์˜ ์˜ˆ์ œ๋Š” ๋ฐ์ฝ” ๋ ˆ์ดํŒ… ๋œ ํ•จ์ˆ˜๊ฐ€ ๋ชจ๋“ˆ ๋˜๋Š” ํด๋ž˜์Šค ๋ฒ”์œ„์—์žˆ๋Š” ๊ฒฝ์šฐ ์—๋งŒ ์ž‘๋™ํ•˜๋ฉฐ,์ด ๊ฒฝ์šฐ ๋ชจ๋“ˆ ๋˜๋Š” ํด๋ž˜์Šค๋Š” ํ•จ์ˆ˜์— ๋Œ€ํ•œ ๊ฐ•๋ ฅํ•œ ์ฐธ์กฐ๋ฅผ ๊ณ„์† ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์œ ์ผํ•œ ๊ฐ•๋ ฅํ•œ ์ฐธ์กฐ๋Š” ์ •์˜ ๋œ ๋ฒ”์œ„์˜ ๋์—์„œ ์ฃฝ์Šต๋‹ˆ๋‹ค.

์œ„์— ๋‚˜์—ด๋œ ๊ฒฝ์šฐ์—์„œ ์ž‘๋™ํ•˜๋Š” weak=False ์ „๋‹ฌํ•˜๋„๋ก ๋ฌธ์„œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” Django ์ปจํ…์ŠคํŠธ์—์„œ ์ด๊ฒƒ์„ ๋ช…์‹œ ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ฃผ๊ธฐ์ ์ธ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด -B ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…์ž๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ ์Šค์ผ€์ค„๋Ÿฌ๋„ ํ˜ธ์ถœํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

celery -A proj worker -B

์ž‘์—…์ด ์• ํ”Œ ๋ฆฌ์ผ€์ด์…˜์—์„œ autodiscoveredํ•˜๋Š” ์žฅ๊ณ  ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ์…€๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ๋‹น์‹ ์€ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ on_after_finalize ๋Œ€์‹ ์— ์‹ ํ˜ธ on_after_configure .

์ฐธ๊ณ  ๋ฌธํ—Œ :
http://stackoverflow.com/questions/40712678/setup-periodic-task/40727526
http://stackoverflow.com/questions/41119053/connect-new-celery-periodic-task-in-django

๋‚ด ๊ณผ์ • python -m celery -A app_name worker -l info --autoscale=20,5 -BE ๋ง์— ์ฐจ๋‹จ app_name.celery.py ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ on_after_finalize .

@ liuallen1981 ๊ณผ ๋™์ผํ•œ ๊ตฌ์„ฑ ๋ฐ ๋™์ผํ•œ ๋ฌธ์ œ. ๋ˆ„๊ตฌ๋‚˜ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ์•„๋ƒ…๋‹ˆ๋‹ค. ์ง€๊ธˆ์€

celery.conf.beat_schedule = {
    'do-something-periodically': {
        'task': 'tasks.my_task',
        'schedule': 3.0,
    },
}

on_after_configure.connect ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ํ•จ๊ป˜ setup_periodic_tasks ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ .

์ด๊ฒƒ์€ ๋Œ€์‹  ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ๋จผ์ € ๋„์ปค ์—”์ง„์„ ์žฌ๋ถ€ํŒ…ํ•˜๋ฉด ์‹œ์Šคํ…œ ๋ฒ„๊ทธ ์‹ ํ˜ธ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์œผ๋กœ ์ข…๋ฃŒํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

@auvipy ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์…€๋Ÿฌ๋ฆฌ ๋ฒ„๊ทธ ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์ˆ˜์ •ํ•ด์•ผํ•˜๋Š” ๋ฒ„๊ทธ์ž…๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰