我们最近使用 gevent 工作人员切换到 Gunicorn 。
在我们的网站上,我们有一些需要一段时间才能完成的任务。超过30秒。
我们已经完成了整个芹菜的事情,但是这些任务很少运行,以至于不能让celery和redis一直运行。我们只是不想那样。我们也不想按需开始芹菜和红葡萄酒。我们想要摆脱它。 (我很抱歉这个,但我想阻止这样的答案:"为什么不使用芹菜,它太棒了!")
我正在谈论执行3000个SQL查询(插入)的任务,这些查询必须一个接一个地执行。 这种情况并非经常发生。我们仅限于同时运行其中两项任务。他们应该采取 2-3分钟。
现在,我们现在正在做的是利用gevent worker和gevent.spawn
任务并返回响应。
我发现生成的线程实际上是阻塞的。一旦返回响应,任务就会开始运行,并且在任务停止运行之前不会处理任何其他请求。这项任务将在30多岁后被枪杀timeout
。
为了防止这种情况,我在每个其他SQL查询之后使用time.sleep()
,因此服务器有机会响应请求,但我不觉得这是重点。
我们运行gunicorn,django并使用gevent。描述的行为发生在我的开发环境中并使用1 gevent worker。在生产中,我们也只运行一名工人(现在)。此外,在任务阻塞时,运行2名工作人员似乎无助于提供更多请求。
谢谢!
答案 0 :(得分:0)
在后台运行任务的一种方法是fork
父进程。与Gevent不同,它不会阻止 - 你运行两个完全独立的进程。这比开始另一个(非常便宜的)greenlet慢,但在这种情况下,这是一个很好的权衡。
您的流程分为两部分,即父级和子级。在父母身上,return
对Gunicorn的回应就像普通代码一样。
在孩子身上,进行长时间的处理。最后,通过执行exit
的专用版本进行清理。这是一些处理和发送电子邮件的代码:
if os.fork():
return JsonResponse({}) # async parent: return HTTP 200
# child: do stuff, exit quietly
ret = do_tag_notify(
event, emails=emails, photo_names=photo_names,
)
logging.info('do_tag_notify/async result={0}'.format(ret))
os._exit(0) # pylint: disable=W0212
logging.error("async child didn't _exit correctly") # never happens
小心这一点。如果孩子抛出异常,即使是语法错误或未使用的变量,你也永远不会知道它!记录的父级已经消失。记录日期冗长,不要做太多。
使用fork
是一个有用的工具 - 玩得开心!
答案 1 :(得分:0)
我已决定使用synchronous
(标准)工作人员并使用multiprocessing
库。这似乎是目前最简单的解决方案。
我还实现了一个全局池滥用提供锁定的memcached
缓存,因此只能运行两个任务。
答案 2 :(得分:0)
这似乎没有人在这里提出你的问题。
阻止意图或我们的设置是否错误?
您的设置有问题。 SQL查询几乎完全受I / O限制,不应阻止任何greenlet。您要么使用不是gevent友好的SQL / ORM库,要么代码中的其他内容导致阻塞。您不应该为这种任务使用多处理。
除非您在greenlets上明确地执行join
,否则服务器响应不应该阻塞。