我正在使用 Python 3.10.11、Flask 3.0.0 和 Werkzeug 3.0.1。 我在一个项目上工作了几个月,休息了一下,现在,几个月后,由于某种原因,热重载不起作用。相反,它会抛出此错误。此外,有时即使我重新启动应用程序(关闭并启动新终端),应用程序也不会更新。我尝试将这个问题作为环境问题和版本不匹配问题来解决,但这两种解决方案最终都不起作用。我的应用程序中也没有任何套接字。
Exception in thread Thread-2 (serve_forever):
Traceback (most recent call last):
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\threading.py", line 1016, in _bootstrap_inner
self.run()
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\werkzeug\serving.py", line 806, in serve_forever
super().serve_forever(poll_interval=poll_interval)
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\socketserver.py", line 232, in serve_forever
ready = selector.select(poll_interval)
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\selectors.py", line 324, in select
r, w, _ = self._select(self._readers, self._writers, [], timeout)
File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\selectors.py", line 315, in _select
r, w, x = select.select(r, w, w, timeout)
OSError: [WinError 10038] An operation was attempted on something that is not a socket
我正在使用pipenv,尝试以多种方式运行该应用程序。
flask --debug run
py ./app.py
pipenv run py ./app.py
我只是不明白为什么它停止工作。我检查了版本不匹配并尝试更改多个 python 版本以及多个 Flask & Werkzeug 版本,不幸的是没有运气。 我尝试重置 netsh:
netsh winsock reset
,如here所示,但也没有运气。
我尝试删除环境并创建一个新环境。我在全球和本地(在环境中)运行这个应用程序,但遇到了同样的问题。有时在环境中运行它只捕获第一次重新加载,然后停止工作(没有任何重新加载选项)
我一无所知。什么会导致这种情况? 我唯一的猜测是,当它尝试重新加载应用程序时,它会在我无法“Ctrl + C”退出的地方崩溃,这会导致循环损坏整个侦听端口。更改端口也不起作用。
@JohnGordon 和@MarkTolonen 是对的。我花了几个小时试图解决这个问题,甚至不知道是什么线路造成的。我删除了所有逻辑,发现我的主 Flask 应用程序中的行
db = MyDBClass()
导致了错误。
我的数据库类有一个函数,该函数在一个单独的、分离的线程中运行,该线程处理其请求队列。由于大量请求同时传入,因此该线程对于我的数据库来说是必须的,以免混合提供给请求的结果。热重载 Flask 应用程序创建了多个数据库实例,这些实例创建了连接到同一数据库的多个线程。两个线程无法访问同一数据库,因此我们收到此错误。
import logging
import threading
from flask_cors import CORS
from flask import Flask, request
# Other imports
app = Flask(__name__)
db = PostgreDB()
# Causes an error because a hot-reload will create multiple threads using the same database here
def restart_db():
global db
db = PostgreDB() # < Error
@app.route('/')
def index():
return "Hurray!"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5500, debug=True)
g
Flask 为我们提供了一个在应用程序上下文中使用的全局命名空间。根据 Flask 的文档:
通常,应用程序上下文与请求具有相同的生命周期。
因此,对于每个请求,数据库类都会重新启动。这意味着现在可以在创建新线程之前正确终止线程(当然它的终止必须在
YourDBClass.__del__()
中实现)。现在,热重载时不会创建多个线程,因此问题已解决。
代码:
import logging
import threading
from flask_cors import CORS
from flask import Flask, request
# Other imports
def get_db():
'''
Function inserts db into Flask global variable namespace
which shutdowns after appcontext dies
'''
if 'db' not in g:
g.db = MyDB() # create a new database connection
return g.db
# Create Flask app
def create_app():
app = Flask(__name__)
# Register FLASK ROUTES:
@app.route('/')
def index():
name = g.db.get_name({"id": 123}) # < How to use db class in your code
return f"Hurray {name}"
@app.before_request
def before_request():
g.db = get_db()
@app.teardown_appcontext
def teardown_db(exception):
db: MyDB | None = g.pop('db', None)
if db is not None:
db.close()
return app
if __name__ == '__main__':
app = create_app()
app.run(host='0.0.0.0', port=5500, debug=True)
现在可能出现的一个问题是效率,因为为每个请求创建数据库类实例。这种开销可以通过 Postgresql 连接池(重用数据库连接)来减少。目前,我的数据库收到的连接数不足以导致此错误,因此我暂时保留它。