我有要求:
有没有办法让芹菜做到这一点?
由于
答案 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)
很难说你应该采取哪种方法,因为这取决于你的申请。
希望它可以帮到你!
祝你好运!