Пока что я реализовал такое решение, работает довольно хорошо.Но я не совсем уверен, что max_retries = None утверждает, что количество повторных попыток будет неограниченным.Это решение работает на Redis, но может работать на любом другом движке, который поддерживает атомарную операцию приращения.
@task(max_retries=None,default_retry_delay=3)
def sleepTask():
if r.incr('sleep_working')>1:
r.incr('sleep_working',-1)
sleepTask.retry()
else:
try:
r.expire('sleep_working',3600)
sleep(30)
finally:
r.incr('sleep_working',-1)
return True
Ключевым моментом здесь является то, что incr атомарно, поэтому никогда не случится, что два клиента получат счетчик== 1.
Кроме того, истечение срока очень важно, все может произойти, и мы получим наш счетчик> 1 навсегда, поэтому expire гарантирует, что, несмотря ни на что, после определенного времени счетчик будет сброшен.Это значение может быть скорректировано с учетом потребностей.У меня загрузка больших файлов, так что 3600 звучит нормально.
Я думаю, что это хорошая отправная точка, чтобы создать собственный объект Task, который будет делать все это автоматически, получая значения redis_key и expire_time.Я буду обновлять этот пост, если я сделаю такую задачу.
В качестве бонуса это решение также можно легко настроить на 2/3 / любое другое число параллельных лимитов, изменив> 1 на> любое число