使用信号句柄关闭flask-socketio服务器

问题描述 投票:0回答:1

我正在使用macOS Mojave和Python 3.7。在我的工作中,我想完全从信号处理程序中关闭flask-socketio服务器,该信号处理程序在我的代码中定义为SignalHandler。我注意到,如果没有信号处理程序,则可以使用Ctrl-C完全关闭服务器。但是,信号处理程序是我工作所必需的。我在网上搜索,但找不到针对我的情况关闭服务器的解决方案。供您参考,我找到了通过“ call flask-socketio stop from HTTP or SocketIO handler function”或“ shut down a gevent (pywsgi) server gracefully”关闭服务器的解决方案。

示例代码如下:

import os
import threading
import signal
import requests

from flask import Flask, send_from_directory
from flask_socketio import SocketIO, Namespace
import eventlet


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

    def run(self):
        app = Flask(__name__, template_folder="templates",
                    static_folder="templates/static")

        app.config['SECRET_KEY'] = 'Secret!'
        socketio = SocketIO(app, engineio_logger=True, logger=True)

        # Create a URL route in our application for "/"
        @app.route('/')
        def test_page():
            """
            This function loads the homepage
            """
            return send_from_directory(
                os.path.join(app.root_path, 'templates'),
                "index1.html"
            )

        @app.route('/stop', methods=['POST'])
        def shutdown_server():
            """
            This function stops the flask-socketio server
            """
            print("Received request to shut down the server.")
            socketio.stop() #something wrong here, but don't know how to solve
            return "The server has been shut down."

        class MyCustomNamespace(Namespace):
            def on_connect(self):
                print("Client just connected")

            def on_disconnect(self):
                print("Client just left")

            def on_messages(self, data):
                print(f"\nReceived data from client: \n {data}\n")
                return data

        socketio.on_namespace(MyCustomNamespace('/channel_A'))

        try:
            eventlet.wsgi.server(
                eventlet.wrap_ssl(eventlet.listen(("localhost", 8080)),
                                  certfile='server.crt',
                                  keyfile='server.key',
                                  server_side=True), app)
        except Exception as e:
            print(f"Website is not established due to:\n{e}")


# Terminate code from shell
class SignalHandler(object):
    def __init__(self):
        pass

    def __call__(self, signum, frame):
        print("Shutting down the website.")

        # Begin 'something' here to shut down the server...
        shutdown_server = requests.post("https://localhost:8080/stop", data=None)
        print(f"Shut down the server feedback: {shutdown_server}")
        # 'Something' ends here

        print("The website has been shut down.")


if __name__ == '__main__':

    WebsiteCreator().start()

    # If the following part is not included, the server can be shut down using Ctrl-C
    handler = SignalHandler()
    signal.signal(signal.SIGINT, handler)

在代码中,我正在线程中运行flask-socketio服务器。我想通过在SignalHandler中执行一些操作来关闭服务器。

但是,当我使用Ctrl-C退出系统时,出现了一些异常:

^C
Shutting down the website.
(23066) accepted ('127.0.0.1', 49720)
Received request to shut down the server.
127.0.0.1 - - [22/Nov/2019 13:08:18] "POST /stop HTTP/1.1" 200 0 0.000365
wsgi exiting
Exception ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py'>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 1308, in _shutdown
    lock.acquire()
  File "web_app.py", line 74, in __call__
    shutdown_server = requests.post("https://localhost:8080/stop", data=None)        
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/api.py", line 116, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/sessions.py", line 646, in send
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/hubs/kqueue.py", line 105, in wait
    readers.get(fileno, hub.noop).cb(fileno)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/greenthread.py", line 221, in main
    result = function(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 818, in process_request
    proto.__init__(conn_state, self)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 357, in __init__
    self.handle()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 390, in handle
    self.handle_one_request()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 419, in handle_one_request
    self.raw_requestline = self._read_request_line()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 402, in _read_request_line
    return self.rfile.readline(self.server.url_length_limit)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socket.py", line 589, in readinto
    return self._sock.recv_into(b)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/green/ssl.py", line 241, in recv_into
    return self._base_recv(nbytes, flags, into=True, buffer_=buffer)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/green/ssl.py", line 256, in _base_recv
    read = self.read(nbytes, buffer_)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/green/ssl.py", line 176, in read
    super(GreenSSLSocket, self).read, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/green/ssl.py", line 150, in _call_trampolining
    return func(*a, **kw)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 926, in read
    raise ValueError("Read on closed or unwrapped SSL socket.")
    r = adapter.send(request, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/adapters.py", line 498, in send
ValueError: Read on closed or unwrapped SSL socket.
Removing descriptor: 8
142f38bdaaf34c7e8883e99a766fe310: Unexpected error "Read on closed or unwrapped SSL socket.", closing connection
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

请给我一些想法!预先感谢。

server python-3.7 shutdown flask-socketio
1个回答
0
投票

这是我在项目中使用的,使用gevent效果很好。确保在启动信号后启动服务器。信号应相同,只是减去gevent部分。

  def shutdown():
        print('Shutting down ...')
        server.stop(timeout=60)
        exit(signal.SIGTERM)
  gevent.signal(signal.SIGTERM, shutdown)
  gevent.signal(signal.SIGINT, shutdown) #CTRL C
  server.serve_forever()
热门问题
推荐问题
最新问题