如何在一段时间内聚合python任务并仅执行一次每个任务

时间:2015-07-15 12:33:45

标签: python django

考虑一个通用应用程序,每次他们做好事时都会为其用户提供分数

我有模特

 protected function hasInvalidState()
    {
        if ($this->isStateless()) {
            return false;
        }
        $session = $this->request->getSession();
        dd($session);
        dd($this->request->input('state'));
        return ! ($this->request->input('state') === $session->get('state'));
    }

现在,每次添加新契约时,都会重新计算该用户的总分数,并且每次重新计算用户的分数时,也会重新计算所有用户(针对其他用户)的排名。

这太可怕了,我想聚合所有排名更新请求,并且每隔几分钟只执行一次。有没有python库可以做这样的事情?

cron作业是一种选择,但它会每隔几分钟更新一次所有用户的排名,无论是否需要更新。

编辑:基于@The Django Ninja的建议,我写了这个装饰并分享它

USAGE:

class GoodDeed(models.Model):
     user = models.ForgeinKey(CustomUser)
     points = models.IntegerField(default=0, blank=True)

class CustomUser(models.Model):
     points = models.IntegerField(default=0, blank=True)
     rank = models.IntegerField(blank=True, null=True)

的影响

    class CustomUser(models.Model):

        @cached_model_property
        def points(self):
            del self.rank  # removed cached rank value
            return sum(self.good_deeds.values_list("points", flat=True))

        @cached_model_property(readonly=False)
        def rank(self):
            user_list = []
            for user in User.onjects.all().only("points")
                user_list.push((user.points, user))
            # sort the list
            user_list.sort(reverse=True)
            # update all ranking
            rank = 0
            my_rank = None
            for points, user in user_list:
                rank += 1
                if user.pk == self.pk:
                    # Don't update this instance's rank yet, as it will be
                    # updated when the function return
                    my_rank = rank
                    continue
                # Save the new rank in the cache
                user.rank = rank
            # If you forget to return something (not None) caching will always assumed to be invalid
            return my_rank

id为20的用户的缓存排名值将存储在名为的缓存键中 'User.20.rank'

装饰员代码

>>> user.points
# call points() method, cache the result, return it
>>> user.points
# return cached result without calling points() method
>>> del user.points
>>> user.points
# call points() method, cache the result, return it

>>> user.rank
# 1. Calculate and save (in cache) rank of all users except current user
# 2. Cache current user's rank and return it
>>> user.rank
# return cached user's rank
>>> del user.points
>>> user.rank
# Recalculate user's points and all ranking values 
>>> user.points = 9
# Readonly property exception

2 个答案:

答案 0 :(得分:2)

如上所述,排名任务似乎在数据库上做了一些重要的工作。

我会选择基本的缓存失效解决方案,如果更新了用户排名,缓存应该无效:

from django.core.cache import cache

def the_function_that_update_user_rank()
    # updating the rank of the user
    # when the rank is updated we set our cache key (global-rank-update-needed) to True
    cache.set('global-rank-update-needed', 'True')

然后一个cron作业应该每隔x秒调用一次manage.py命令,如果'global-rank-update-needed'为True,命令将从缓存中检查,然后更新全局等级:

from django.core.cache import cache

class UpdateGlobalRank(BaseCommand):
    help = 'Closes the specified poll for voting'


    def handle(self, *args, **options):
        if cache.get('global-rank-update-needed') == 'True':
            # here do the update rank stuff
            print 'Updating the Global Rank'
        cache.set('global-rank-update-needed', 'False')                         

遵循此方法,只有在某些用户的排名发生变化时才会更新全局排名

希望它有所帮助。

答案 1 :(得分:0)

我更喜欢celery这类任务。

是一个任务队列,专注于实时处理,同时还支持任务调度