使用Celery安排和重新安排帖子时遇到问题

3 投票
1 回答
1715 浏览
提问于 2025-04-16 08:54

我正在做一个Django博客,想要能安排文章在未来的某个时间发布。Celery在最初安排文章时效果很好,但当用户想要更新文章,比如重新安排发布时间或者取消发布时,我就遇到了一些问题。

我想要做的是:

def save(self, **kwargs):
    ''' 
    Saves an event. If the event is currently scheduled to publish, 
    sets a celery task to publish the event at the selected time.  
    If there is an existing scheduled task,cancel it and reschedule it 
    if necessary.
    ''' 
    import celery
    this_task_id = 'publish-post-%s' % self.id 
    celery.task.control.revoke(task_id=this_task_id)

    if self.status == self.STATUS_SCHEDULED:
        from blog import tasks
        tasks.publish_post.apply_async(args=[self.id], eta=self.date_published,
                task_id=this_task_id) 
    else:
        self.date_published = datetime.now()

    super(Post, self).save(**kwargs)

问题是,一旦一个Celery任务的ID被标记为撤销,它就会一直保持撤销状态,即使我尝试重新安排它。这看起来是一个比较常见的任务,应该有简单的解决办法。

1 个回答

3

我不知道你的tasks.py文件长什么样,但我猜它大概是这样的:

from celery.decorators import task

@task
def publish_post(post_id):
    ''' Sets the status of a post to Published '''
    from blog.models import Post

    Post.objects.filter(pk=post_id).update(status=Post.STATUS_PUBLISHED)

你应该在任务里修改过滤条件,确保当前状态是STATUS_SCHEDULED,并且date_published里的时间已经过去了。例如:

from celery.decorators import task

@task
def publish_post(post_id):
    ''' Sets the status of a post to Published '''
    from blog.models import Post
    from datetime import datetime

    Post.objects.filter(
        pk=post_id,
        date_published__lte=datetime.now(),
        status=Post.STATUS_SCHEDULED
    ).update(status=Post.STATUS_PUBLISHED)

这样一来,用户就可以随意更改状态和时间,任务只有在date_published的时间之后才会把状态改为发布。这样就不需要去追踪ID或者撤销任务了。

撰写回答