有没有办法在芹菜中定义任务配额?

时间:2015-09-30 05:50:11

标签: django celery amqp

我有要求:

  1. 我几乎没有繁重的资源消耗任务 - 导出需要大量复杂查询的不同报告,子查询
  2. 有很多用户。
  3. 我在django中构建了项目,并使用celery排队任务
  4. 我想限制用户,以便他们每分钟可以请求10个报告。这个想法是他们可以把数百个请求放10分钟,但我希望芹菜为用户执行10个任务。这样每个用户都可以轮到他们了。
  5. 有没有办法让芹菜做到这一点?

    由于

1 个答案:

答案 0 :(得分:1)

Celery有一个设置来控制RATE_LIMIT(http://celery.readthedocs.org/en/latest/userguide/tasks.html#Task.rate_limit),这意味着可以在一个时间范围内运行的任务数。 您可以将其设置为' 100 / m' (每秒一百次)管理你的系统允许每秒100个任务,重要的是要注意,设置不是每个用户既不是任务,也不是每个时间帧。 您是否考虑过这种方法而不是限制每个用户?

为了获得' rate_limit'每个任务和用户对,您将不得不这样做。我认为(不确定)你可以根据你的需要使用TaskRouter或信号。 TaskRouters(http://celery.readthedocs.org/en/latest/userguide/routing.html#routers)允许将任务路由到某个逻辑的指定队列。 信号(http://celery.readthedocs.org/en/latest/userguide/signals.html)允许在任务的调度周期的几个明确定义的点中执行代码。

路由器逻辑的一个例子可能是:

if task == 'A':
    user_id = args[0]  # in this task the user_id is the first arg
    qty = get_task_qty('A', user_id)
    if qty > LIMIT_FOR_A:
        return
elif task == 'B':
    user_id = args[2]  # in this task the user_id is the seconds arg
    qty = get_task_qty('B', user_id)
    if qty > LIMIT_FOR_B:
        return
return {'queue': 'default'}

使用上面的方法,每次任务开始时,你应该在某个地方(例如Redis)增加一对user_id / task_type和 每次任务完成时,你应该在同一个地方减少该值。

它似乎有点复杂,难以维护,对我来说几乎没有失败点。

我认为可以采用的其他方法是实现某种“分布式信号量”' (每个用户和任务类似于分布式锁定),因此在需要限制任务运行次数的每个任务中,您都可以使用它。

这个想法是,每次一个应该具有“并发控制”的任务时。开始它必须检查是否有一些资源可用,如果不只是返回。

你可以想象这个想法如下:

@shared_task
def my_task_A(user_id, arg1, arg2):
    resource_key = 'my_task_A_{}'.format(user_id)
    available = SemaphoreManager.is_available_resource(resource_key)
    if not available:
        # no resources then abort
        return

    try:
        # the resourse could be acquired just before us for other
        if SemaphoreManager.acquire(resource_key):
            #execute your code
    finally:
        SemaphoreManager.release(resource_key)

很难说你应该采取哪种方法,因为这取决于你的申请。

希望它可以帮到你!

祝你好运!