使用celery异步执行Django应用程序的任务

时间:2016-05-25 17:56:11

标签: django django-models redis django-views celery

在我维护的Django应用程序中,用户登录并互相交换消息,论坛风格。在任何给定的时间点,我通过检查在最后5分钟内登录session对象的人来显示谁在线。为了实现这一点,我使用Django插件user_sessions,允许像常规ORM一样操作会话。

我完成此任务的代码是:

class WhoseOnlineView(ListView):
    model = Session
    template_name = "whose_online.html"

    def get_queryset(self):
        unique_user_sessions = Session.objects.filter(last_activity__gte=(timezone.now()-timedelta(minutes=5))).only('user').distinct('user')
        users = [session.user for session in unique_user_sessions]
        users = [user for user in users if user is not None] #sanitizing None values
        return users

网站的用户(和功能)已大幅增长,而且根据newrelic,此特定视图在我的所有视图中消耗的时间最多。

我认为我应该将整个任务移动到异步完成。我在我的生产服务器上使用cevis(使用redis作为消息代理)并在supervisord下运行。

这可能是一项定期任务,每60秒执行一次。但似乎要实现这一点,我需要在数据库(或缓存)中保存结果,以便用户可以看到保存的结果,直到下次其在线列表处理完毕。

有人可以给我一个关于如何实现这个目标的说明性例子吗?我努力解决的主要问题是如何在下一个周期性任务开始之前保存(或缓存)随后显示给用户的结果。

1 个答案:

答案 0 :(得分:0)

您可以执行以下操作:

首先,编写芹菜任务以找出登录用户,例如

# fooapp.tasks

@shared_task
def whoseonline(): 
    unique_user_sessions = Session.objects.filter(last_activity__gte=(timezone.now()-timedelta(minutes=5))).only('user').distinct('user')
    users = [session.user for session in unique_user_sessions        users = [user for user in users if user is not None] #sanitizing None values
    # save the users to the cache
    cache.set('online_users', users, 70)  # expiring in 70 seconds

并设置任务以便运行一定的时间,例如60秒,加上这个:

# settings.py

CELERYBEAT_SCHEDULE = {
    'whoseonline': {
        'task': 'fooapp.tasks.whoseonline',
        'schedule': timedelta(seconds=60),  # execute every 60 seconds
        'args': (),
    },
}

到您的设置。然后,在您的视图中,您只需要执行

class WhoseOnlineView(ListView):
    model = Session
    template_name = "whose_online.html"

    def get_queryset(self):
        # take the values from the cache
        return cache.get('online_users')

Here更多关于缓存和here更多关于芹菜的信息。

您还应该记住,缓存时间到期(样本中的70秒)应该大于您将用于芹菜任务的预定时间(样本中为60秒),以便视图始终具有某些内容秀。