如何仅多次运行Celery计划,直到再次调用该任务?

时间:2019-10-09 16:20:56

标签: python django redis celery

我正在使用django + celery任务计划程序来运行每月计划一次的任务。但我只希望此任务仅运行几个月,例如3个月或6个月或9个月。

如何使工作人员停止执行其他任务,然后在再次调用该任务时重新启动?

这是我的任务

@task(name="add_profit")
def count():
    portfolios = Portfolio.objects.filter(status='ACTIVE')
    if portfolios.exists():
        for portfolio in portfolios:
            user = portfolio.user
            #calculates portfolio profit
            amount = portfolio.amount * 0.1
            if portfolio.duration == '3 Months':
                PortfolioProfit.objects.create(user=user, amount=amount)
                user.useraccount.account_balance += amount
                user.useraccount.save()

这是我的芹菜任务时间表

app.conf.beat_schedule = {
    # Executes 1st day of every Month.
    'every-minute': {
        'task': 'add_profit',
        # crontab can be changes to change Schedule
        # http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html
        'schedule': crontab(0, 0, day_of_month = 1),
    },
}


3 个答案:

答案 0 :(得分:0)

选项1: 您每个月都用celery crontab条目开始任务,并在任务中添加测试:如果当前日期不在特定范围内,则您就退出处理。

这会有一点开销,但是每月一次的视线开销应该可以接受。

@task(name="add_profit")
def count():
    today = datetime.datetime.now()
    if today > datetime.datetime(2020,1, 1):
        return
    # the remaining part of your task follows here

选项2: 您只需执行一次(无论是否有for循环)一个小代码段,即可计划相关月份的任务。

http://docs.celeryproject.org/en/latest/userguide/calling.html#eta-and-countdown

在下面的示例中,我仅演示了如何计划接下来的三天任务:

today = datetime.utcnow()

for delta in range(1, 4):
    task.apply_async(args=[arg1, arg2, ...), eta=today + timedelta(days=delta))

在这里,任务将完全按照您想要的频率执行。

但是,如果将服务器迁移到其他位置,则如果重置Rabbitmq(或您拥有的任何代理),则计划的任务将丢失/消失

答案 1 :(得分:0)

提出新答案。我想保留上一个,因为它可能会帮助其他有其他问题的人。对于您的问题,我想您只需要每月无条件调用芹菜任务即可。

我认为,最简单的方法是更改​​存储在数据库中的数据,以便可以标识活动的投资组合,存储第一次要添加日期的日期和最后一次要添加值的日期。

现在,每月一次的celery任务将标识first_date <=今天<= last_date的用户,并在条件为真时添加值。

答案 2 :(得分:0)

好。非常感谢@gelonida的输入。我已经能够实现我的目标。

我创建了一个有效期的数据库输入(3个月,6个月等,具体取决于用户的选择),它是根据创建投资组合的日期和将来的某个时间计算的,如下所示:

portfolio.expiry_date = timezone.now() + timedelta(days = 93) # for 3months

然后在我的任务中,我做了

from django.utils import timezone


@task(name="add_profit")
def count():
    portfolios = Portfolio.objects.filter(status='ACTIVE')
    current_datetime = timezone.now()
    if portfolios.exists():
        for portfolio in portfolios:
            if current_datetime > portfolio.expiry_date:
                portfolio.status = 'COMPLETED'
                portfolio.save()
                return
            else:
                user = portfolio.user
                amount = portfolio.amount * 0.1
                PortfolioProfit.objects.create(user=user, amount=amount)
                user.useraccount.account_balance += amount
                user.useraccount.save()

这对我来说很好。