4

我知道(通过搜索和检查 gevent 的源)正常关闭基于 gevent WSGI 的服务器的唯一方法是:

server = gevent.wsgi.WSGIServer(('', 80), someWSGIApp)
def shutdown():
  print('Shutting down ...')
  server.stop(timeout=60)
  exit(signal.SIGTERM)
gevent.signal(signal.SIGTERM, shutdown)
server.serve_forever()

现在,我所说的优雅的意思是等待所有的greenlet自行终止。因此,例如,如果他们仍在处理请求,他们可以正确完成它们。

问题是,使用上面看似正确的代码,服务器确实在等待最大值。60 秒,但所有 TCP 连接在收到SIGTERM. 然而,Greenlets 会继续做他们原来的事情(例如睡觉),直到他们完成或发生超时。

有任何想法吗?

4

3 回答 3

2

您可以通过在一个线程中运行服务器并在另一个线程中关闭它来解决该问题。下面的代码在 Python 3.7 中运行。

from gevent.pywsgi import WSGIServer
import signal
import threading

# define your app here
app = ...

server_address = ("localhost", 4000)


class WebServer(threading.Thread):
    def __init__(self):
        super().__init__()

    def run(self):
        global server
        server = WSGIServer(server_address, app)
        server.serve_forever()


def shutdown(num, info):
    print(f'Shutting down website server...\n'
          f'{num} {info}')
    server.stop()
    server.close()


if __name__ == "__main__":
    server = None
    WebServer().start()

    signal.signal(signal.SIGINT, shutdown)
于 2019-10-21T15:53:34.060 回答
1

正如文档字符串在服务器的停止方法中所说(gevent.baseserver.BaseServer:stop)

Stop accepting the connections and close the listening socket.

If the server uses a pool to spawn the requests, then :meth:`stop` also 
for all the handlers to exit. 
If there are still handlers executing after *has expired (default 1 second), 
then the currently running handlers in the pool are killed.

我没有尝试过,但如果文档是正确的,您应该能够通过以下方式优雅地停止:

from gevent.pool import Pool

pool_size = 8
worker_pool = Pool(pool_size)
gevent.wsgi.WSGIServer(('', 80), someWSGIApp, spawn=worker_pool)
于 2013-08-23T10:52:13.523 回答
0

但所有 TCP 连接在收到 SIGTERM 后立即终止。

我有一个类似但不完全相同的问题......

...我的问题是,即使连接仍在进行中,Python 进程也会退出。我通过添加gevent.get_hub().join()后解决了这个问题server.serve_forever()

server = gevent.wsgi.WSGIServer(('', 80), someWSGIApp)
gevent.signal(signal.SIGTERM, server.stop)
server.serve_forever()
gevent.get_hub().join()
于 2019-08-09T12:24:20.570 回答