我有几个任务,如下:
CELERYBEAT_SCHEDULE = {
'task1': {
'task': 'api.tasks.task1',
'schedule': timedelta(seconds=10),
},
'task2': {
'task': 'api.tasks.task2',
'schedule': timedelta(seconds=30),
},
'task3': {
'task': 'api.tasks.task3',
'schedule': timedelta(seconds=15),
},
...
}
因此,task1将在*:*:10,*:*:20,*:*:30,*:*:40,*:*:50和*:*:00
中运行task2将在*:*:30和*:*:00
中运行task3将在*:*:15,*:*:30,*:*:45和*:*:00
中运行然后任务总是在*:*:30和*:*:00中同意。有没有办法添加偏移量。我想得到这样的东西:
task1(offset = 2)在*:*:12,*:*:22,*:*:32,*:*:42,*:*:52和*:*:02
中运行task2(offset = 7)在*:*:37和*:*:07
中运行task3(offset = 0)在*:*:15,*:*:30,*:*:45和*:*:00
中运行我已经阅读了文档,我想我必须使用crontab,但是不是有另外一种方式更好吗?并且crontab没有秒配置: - (
答案 0 :(得分:1)
您可以使用以下步骤解决此问题:
1.您不需要在CELERYBEAT_SCHEDULE
文件上添加settings.py
2.在__init__.py
app中的api
文件中添加以下代码:
import tasks
3.然后在tasks.py
文件:
from datetime import datetime
from celery import Celery
app = Celery()
run_id = None
@app.task
def task1():
print('every 10 seconds:', datetime.now().second)
@app.task
def task2():
print('every 30 seconds:', datetime.now().second)
@app.task
def task3():
print('every 15 seconds:', datetime.now().second)
@app.task
def run(sender):
global app, run_id
# Schedule other tasks
sender.add_periodic_task(10.0, task1.s())
sender.add_periodic_task(30.0, task2.s())
sender.add_periodic_task(15.0, task3.s())
# Stop self running later times
app.control.revoke(run_id)
@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
global run_id
now = datetime.now()
run_id = sender.add_periodic_task((30 if now.second < 30 else 60) - now.second, run.s(sender))
答案 1 :(得分:1)
您还可以通过扩展自定义自定义计划类型 schedule的界面。
所以这是我的解决方案:
from datetime import timedelta
from celery import Celery
from celery.schedules import schedule
class MySchedule(schedule):
def __init__(self, run_every=None, offset=None):
self._run_every = run_every
self._offset = offset if offset is not None else timedelta(seconds=0)
self._do_offset = True if self._offset else False
super(MySchedule, self).__init__(
run_every=self._run_every + self._offset)
def is_due(self, last_run_at):
ret = super(MySchedule, self).is_due(last_run_at)
if self._do_offset and ret.is_due:
self._do_offset = False
self.run_every = self._run_every
ret = super(MySchedule, self).is_due(last_run_at)
return ret
def __reduce__(self):
return self.__class__, (self._run_every, self._offset)
app = Celery('tasks', broker='pyamqp://guest@localhost//')
app.conf.beat_schedule = {
'task1': {
'task': 'tasks.task1',
'schedule': MySchedule(
run_every=timedelta(seconds=10), offset=timedelta(seconds=2)),
},
'task2': {
'task': 'tasks.task2',
'schedule': MySchedule(
run_every=timedelta(seconds=30), offset=timedelta(seconds=7)),
},
'task3': {
'task': 'tasks.task3',
'schedule': MySchedule(
run_every=timedelta(seconds=15), offset=timedelta(seconds=0)),
},
}
@app.task
def task1():
print('task1')
@app.task
def task2():
print('task2')
@app.task
def task3():
print('task3')
您可以自己编写MySchedule
并从BaseSchedule
扩展它以获得更多控制权。
答案 2 :(得分:-1)
我试图用一种与vasi1y解决方案略有不同的解决方案来解决这个问题。但是这个解决方案和之前的解决方案都不起作用......
class schedule_offset(schedule):
def __init__(self, run_every=None, offset=None,
relative=False, nowfun=None, app=None):
self._run_every = run_every
if offset is None:
offset = 0
self._offset = maybe_timedelta(offset)
self._executing = 0
super(schedule_offset, self).__init__(
run_every=self._run_every, relative=relative, nowfun=nowfun, app=app)
def is_due(self, last_run_at):
last_run_at = last_run_at + self._offset
last_run_at = self.maybe_make_aware(last_run_at)
rem_delta = self.remaining_estimate(last_run_at)
remaining_s = timedelta_seconds(rem_delta)
if remaining_s == 0:
ret = schedstate(is_due=True, next=self.seconds + self._offset.seconds)
if self._executing < 2:
self._executing += 1
if self._executing == 2:
self._offset = maybe_timedelta(0)
return ret
return schedstate(is_due=False, next=remaining_s)
def __reduce__(self):
return self.__class__, (self._run_every, self._offset, self.relative, self.nowfun)
CELERYBEAT_SCHEDULE = {
'task1': {
'task': 'api.tasks.task1',
'schedule': schedule_offset(timedelta(seconds=10), offset=2),
},
'task2': {
'task': 'api.tasks.task2',
'schedule': schedule_offset(timedelta(seconds=30), offset=7),
},
'task3': {
'task': 'api.tasks.task3',
'schedule': timedelta(seconds=15),
},
...
}