如何使用Celery安排一项任务,该任务在三个月后只能运行一次

时间:2020-02-08 21:03:16

标签: django celery

我在Websilte中使用django创建了一个广告应用,广告模型如下所示

AdModel(models.Model):

    starting_date = models.DateField()
    expiring_date = models.DateField()
    active = models.BooleanField(default=False)

我的目标是使用芹菜创建一个任务来激活(设置ad.active = True)并根据其开始日期和到期日期停用广告,并且由于芹菜节拍是用于周期性的重复任务,它不会解决它。

可能将 starting_date 作为eta传递给这样的任务将是解决方案:

#signals.py
@receiver(post_save, sender=AdModel)
def start_task(sender, instance, created, **kwargs):
    if created:
        ad_activator_task.apply_async( (instance.id), eta=instance.starting_date)

如果 instance.starting_date 距现在还有3个月了,它将执行吗?我已经读过Celery not usefull for long term future tasks (far future),我有点困惑。

注意:我将Redis用作经纪人

2 个答案:

答案 0 :(得分:0)

我强烈建议将其与计划任务一起实施。最好还是不要使用const express = require('express'); const bodyParser = require('body-parser'); const proxy = require('http-proxy-middleware'); const httpStatus = require('http-status-codes'); const app = express(); app.use(bodyParser.json()); app.use(function (req, res, next) { console.log("this is where you transform the request"); }); function restreamReq(proxyReq, req, res) { if (!req.body) { return; } const contentType = req.get('content-type'); if (contentType) { proxyReq.setHeader('content-type', contentType); } const contentLength = req.get('content-length'); if (contentLength) { const bodyData = JSON.stringify(req.body); const bufferLength = Buffer.byteLength(bodyData); if (bufferLength != contentLength) { console.warn(`buffer length = ${bufferLength}, content length = ${contentLength}`); proxyReq.setHeader('content-length', bufferLength); } proxyReq.write(bodyData); } } function restreamRes(proxyRes, req, res) { res.status(proxyRes.statusCode); for (const key of Object.keys(proxyRes.headers)) { let rawValue = proxyRes.headers[key]; if (!Array.isArray(rawValue)) { rawValue = [ rawValue ]; } for (const value of rawValue) { res.set(key, value); } } console.log("this is where you transform the response"); let body = new Buffer(''); const bodyPromise = new Promise(function(resolve, reject) { proxyRes.on('data', (data) => body = Buffer.concat([body, data])); proxyRes.on('end', () => resolve()); proxyRes.on('error', (err) => reject(err)); }); bodyPromise .then(() => res.end(body)) .catch(err => res.status(httpStatus.INTERNAL_SERVER_ERROR).end()); } app.use(proxy({ target: 'http://localhost:8080', changeOrigin: true, xfwd: false, preserveHeaderKeyCase: true, selfHandleResponse: true, onProxyReq: restreamReq, onProxyRes: restreamRes, })); const server = app.listen(process.env.PORT || 8081); process.on('SIGINT', function() { server.close(); process.exit(); }); 字段:这里的广告是否有效取决于activestarting_date。因此,我们可以将其建模为:

expiring_date

我们可以使用注释来确定class AdModel(models.Model): starting_date = models.DateField() expiring_date = models.DateField()是否在以下情况下处于活动状态:

AdModel

如果您经常需要这样做,可以制作一个from django.db.models import BooleanField, ExpressionWrapper, Q from django.db.models.functions import Now AdModel.objects.annotate( active=ExpressionWrapper( Q(starting_date__lte=Now(), expring_date__gte=Now()), output_field=BooleanField() ) )来自动注释Manager

AdModel.objects

如果您想要额外的控制,则可以添加一个默认为NULL的额外可空布尔字段class AdModelManager(models.Manager): def get_queryset(self): return super().get_queryset().annotate( active=ExpressionWrapper( Q(starting_date__lte=Now(), expring_date__gte=Now()), output_field=BooleanField() ) ) class AdModel(models.Model): starting_date = models.DateField() expiring_date = models.DateField() objects = AdModelManager(),但可以将其设置为force_active / True来覆盖到期机制:

False

答案 1 :(得分:0)

我想出了一个不错的解决方法,希望创建一个定期执行的任务,该任务每天在午夜运行,以检查广告是否已激活/停用,该任务是这样的:

#tasks.py
@shared_task
def activate_deactivate_ads():
    to_activate = AdModel.objects.filter(date_started=timezone.now().date())
    if to_activate.exists():
        to_activate.update(active=True)

    to_deactivate = AdModel.objects.filter(date_expires=timezone.now().date(), active=True)
    if to_deactivate.exists():
        to_deactivate.update(active=False)

和节拍配置:

#settings.py
CELERY_BEAT_SCHEDULE = {
'activate-deactivate-ads': {
   'task': 'tasks.activate_deactivate_ads',
    # Excecute everyday at midnight
   'schedule': crontab(minute=0, hour=0),
    }
  }

欢迎其他任何方法