【问题标题】:Using celery to asynchronously perform a task for a Django app使用 celery 为 Django 应用程序异步执行任务
【发布时间】:2016-09-23 11:46:55
【问题描述】:

在我维护的一个 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 的说法,在我所有的视图中,这个特定视图消耗的时间最多。

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

这可能是一项周期性任务,每 60 秒执行一次。但似乎要让它工作,我需要在数据库(或缓存)中保存结果,以便用户可以看到保存的结果,直到下一次处理其在线列表.

谁能给我一个说明性的例子来说明如何做到这一点?我正在努力解决的主要问题是如何在下一个定期任务开始之前保存(或缓存)然后显示给用户的结果。

【问题讨论】:

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


    【解决方案1】:

    你可以这样做:

    首先,编写 celery 任务以找出已登录的用户,例如

    # 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 更多关于 celery。

    您还应该记住,缓存时间到期(示例中为 70 秒)应该大于您将用于 celery 任务的计划时间(示例中为 60 秒),以便视图始终有一些东西显示。

    【讨论】:

    • 嗯,我使用的缓存后端是django.core.cache.backends.locmem.LocMemCache。似乎一切都按预期工作,除了我无法正确设置或获取缓存。有什么方法可以测试缓存是否设置正确?我试过django debug toolbar,据此,缓存没有被调用。
    • 你应该看看我传给你的关于缓存的链接。您可以在那里找到如何设置所有缓存机制以及如何使用它
    • 这正是我正在使用的。确切地说,这部分:docs.djangoproject.com/en/1.9/topics/cache/… 这是一个非常严肃的设置,所以我有点难过我所缺少的。
    • 我一直在诊断它,当我尝试 get 视图中存储的结果时,我得到了“无”。奇怪的是,tasks.py 中的get(紧跟在set 之后)工作得非常好。奇怪。
    • 一定要两边使用同一个key,时间足够,随时可用。
    猜你喜欢
    • 2011-11-22
    • 1970-01-01
    • 2012-08-09
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 2016-09-28
    相关资源
    最近更新 更多