2014-09-10 125 views
2

我试图找到一种方法,可以从django管理员打开/关闭芹菜任务。这主要是为了禁用在这些服务关闭或具有计划的维护期时调用外部服务的任务。关掉芹菜任务

对于我的定期任务,这很容易,尤其是在django-celery中。但对于按需调用的任务,我遇到了一些麻烦。目前,我正在探索在TaskControl模型中存储各种任务的开/关状态,然后只在任务执行开始时检查该状态,如果状态为False则返回None。这让我感觉很脏,因为每次任务开始时都会有额外的db查询。我可以使用不是数据库的缓存后端,但为这些少数键/值对添加缓存似乎有点矫枉过正。

在models.py

# this is a singleton model. singleton code bits omitted for brevity. 
class TaskControl(models.Model): 
    some_status = models.BooleanField(default=True) 
    # more statuses 

在tasks.py

@celery.task(ignore_result=True) 
def some_task(): 
    task_control = TaskControl.objects.get(pk=1) 
    if not task_control.some_status: 
     return None 

    # otherwise execute task as normal 

什么是更好的方式来做到这一点?

回答

2

选项1.试试你的简单方法。看看它是否会影响性能。如果没有,就会失去“脏”的感觉。

选项2.使用单例缓存进程内存。加入新鲜的信息到你的TaskControl型号:

class TaskControl(models.Model): 
    some_status = models.BooleanField(default=True) 
    # more statuses 
    expires = models.DateTimeField() 
    check_interval = models.IntegerField(default=5 * 60) 

    def is_stale(self): 
     return (
      (datetime.utcnow() >= self.expires) or 
      ((datetime.utcnow() - self.retrieved).total_seconds >= self.check_interval)) 

然后在task_ctl.py

_control = None 

def is_enabled(): 
    global _control 
    if (_control is None) or _control.is_stale(): 
     _control = TaskControl.objects.get(pk=1) 
     # There's probably a better way to set `retrieved`, 
     # maybe with a signal or a `Model` override, 
     # but this should work. 
     _control.retrieved = datetime.utcnow() 
    return _control.some_status 

选项3.像选项2,但不是基于时间的到期,用芹菜的remote control强迫所有工人重新加载TaskControl(你将不得不编写你自己的控制命令,而且我不知道你需要的所有内部部件是否都是公共API)。

选项4,仅适用于所有芹菜工人都在一台机器上运行。将开/关标志作为文件存储在该机器的文件系统上。用os.path.exists查询它的存在(应该是一个单独的stat()或其他东西,足够便宜)。如果工作人员和管理面板位于不同的计算机上,请使用特殊的Celery任务创建/删除文件。

选项5.与选项4一样,但在管理员/ Web计算机上:如果文件存在,则不要将任务排在首位。

+0

与数字1在一起。性能命中最小,实现也很简单。感谢您的建议! – ecline6 2014-09-13 23:58:42