我需要允许用户提交非常大的作业请求。我们正在谈论100千兆字节的内存和20小时的计算时间。这给我们公司带来了很多钱,因此规定任何时候只能运行2个作业,并且当2个已经运行时对新作业的请求将被拒绝(并且用户通知服务器正忙)。 / p>
我当前的解决方案使用来自concurrent.futures的Executor,并且需要将Apache服务器设置为仅运行一个进程,从而降低响应速度(当前用户数非常低,所以现在可以。)
如果可能的话,我想使用Celery,但我没有在文档中看到任何方法来完成这个特定的设置。
如何在Django应用程序中在后台运行有限数量的作业,并在因服务器忙而拒绝作业时通知用户?
答案 0 :(得分:9)
对于这个特殊情况我有两个解决方案,一个是芹菜的开箱即用解决方案,另一个是你自己实现的解决方案。
您可能也对rate limits感兴趣。
您可以使用选择的锁定解决方案自己完成所有操作。特别是,确保只有两个进程使用redis(和redis-py)运行的一个很好的实现就像下面这样简单。 (考虑到你知道redis,因为你知道芹菜)
from redis import StrictRedis
redis = StrictRedis('localhost', '6379')
locks = ['compute:lock1', 'compute:lock2']
for key in locks:
lock = redis.lock(key, blocking_timeout=5)
acquired = lock.acquire()
if acquired:
do_huge_computation()
lock.release()
break
print("Gonna try next possible slot")
if not acquired:
raise SystemLimitsReached("Already at max capacity !")
这样,您可以确保系统中只能存在两个正在运行的进程。第三个进程将在lock.acquire()
行中阻止 blocking_timeout 秒,如果锁定成功,acquired
将为True,否则为False,您将告诉用户等等!
我过去的某个时候有同样的要求,我最终编码的是上面的解决方案。特别是
答案 1 :(得分:3)
首先,您需要限制工作人员的并发性(docs):
celery -A proj worker --loglevel=INFO --concurrency=2 -n <worker_name>
这将有助于确保即使您的代码中存在错误,也不会有超过2个活动任务。
现在您有两种方法可以实现任务编号验证:
您可以使用inspect获取有效和计划任务的数量:
from celery import current_app
def start_job():
inspect = current_app.control.inspect()
active_tasks = inspect.active() or {}
scheduled_tasks = inspect.scheduled() or {}
worker_key = 'celery@%s' % <worker_name>
worker_tasks = active_tasks.get(worker_key, []) + scheduled_tasks.get(worker_key, [])
if len(worker_tasks) >= 2:
raise MyCustomException('It is impossible to start more than 2 tasks.')
else:
my_task.delay()
您可以在DB中存储当前正在执行的任务数,并根据它来验证任务执行。
如果您想扩展您的功能,第二种方法可能会更好 - 引入高级用户或不允许一个用户执行2个请求。
答案 2 :(得分:2)
<强>第一强>
您需要SpiXel's solution的第一部分。据他说,&#34; 你只创建两个并发= 1 &#34;的工作进程。
<强>第二强>
根据time out为队列中等待的任务设置CELERY_EVENT_QUEUE_TTL,how to limit number of tasks in queue and stop feeding when full?设置为Dead Letter Exchanges,队列长度限制。
因此,当两个工作正在运行的作业,并且队列中的任务等待10秒或您喜欢的任何时间段时,任务将超时。或者如果队列已经完成,则新的到达任务将被取消。
<强>第三强>
当因为服务器忙碌而拒绝工作时,您需要额外的事情来处理通知&#34;用户#34;
https://github.com/bjedrzejewski/tasklist-service就是您所需要的。每次由于队列长度限制或消息超时而导致任务失败。 &#34;一旦达到限制,消息将从队列的前面删除或删除字母,以便为新消息腾出空间。&#34;
您可以将&#34; x-dead-letter-exchange&#34; 设置为路由到另一个队列,一旦此队列收到死信函,您就可以向用户发送通知消息