【发布时间】:2020-08-07 06:49:58
【问题描述】:
我有一个使用 uwsgi 服务器在 Heroku 上运行的 Flask 应用程序,每个用户都连接到他自己的数据库。我已经实现了solution reported here for a very similar situation。特别是,我实现了连接注册表如下:
class DBSessionRegistry():
_registry = {}
def get(self, URI, **kwargs):
if URI not in self._registry:
current_app.logger.info(f'INFO - CREATING A NEW CONNECTION')
try:
engine = create_engine(URI,
echo=False,
pool_size=5,
max_overflow=5)
session_factory = sessionmaker(bind=engine)
Session = scoped_session(session_factory)
a_session = Session()
self._registry[URI] = a_session
except ArgumentError:
raise Exception('Error')
current_app.logger.info(f'SESSION ID: {id(self._registry[URI])}')
current_app.logger.info(f'REGISTRY ID: {id(self._registry)}')
current_app.logger.info(f'REGISTRY SIZE: {len(self._registry.keys())}')
current_app.logger.info(f'APP ID: {id(current_app)}')
return self._registry[URI]
在我的create_app() 中,我为应用分配了一个注册表:
app.DBregistry = DBSessionRegistry()
每当我需要与数据库通话时,我都会致电:
current_app.DBregistry.get(URI)
URI 取决于用户。如果我在一个进程中使用 uwsgi,这会很好地工作。随着更多的进程,
[uwsgi]
processes = 4
threads = 1
有时它会卡在某些请求上,返回 503 错误代码。我发现当请求由uwsgi中的不同进程处理时会出现问题。这是日志的摘录,我对此进行了评论以说明问题:
# ... EVERYTHING OK UP TO HERE.
# ALL PREVIOUS REQUESTS HANDLED BY PROCESS pid = 12
INFO in utils: SESSION ID: 139860361716304
INFO in utils: REGISTRY ID: 139860484608480
INFO in utils: REGISTRY SIZE: 1
INFO in utils: APP ID: 139860526857584
# NOTE THE pid IN THE NEXT LINE...
[pid: 12|app: 0|req: 1/1] POST /manager/_save_task =>
generated 154 bytes in 3457 msecs (HTTP/1.1 200) 4 headers in 601
bytes (1 switches on core 0)
# PREVIOUS REQUEST WAS MANAGED BY PROCESS pid = 12
# THE NEXT REQUEST IS FROM THE SAME USER AND TO THE SAME URL.
# SO THERE IS NO NEED FOR CREATING A NEW CONNECTION, BUT INSTEAD...
INFO - CREATING A NEW CONNECTION
# TO THIS POINT, I DON'T UNDERSTAND WHY IT CREATED A NEW CONNECTION.
# THE SESSION ID CHANGES, AS IT IS A NEW SESSION
INFO in utils: SESSION ID: 139860363793168 # <<--- CHANGED
INFO in utils: REGISTRY ID: 139860484608480
INFO in utils: REGISTRY SIZE: 1
# THE APP AND THE REGISTRY ARE UNIQUE
INFO in utils: APP ID: 139860526857584
# uwsgi GIVES UP...
*** HARAKIRI ON WORKER 4 (pid: 11, try: 1) ***
# THE FAILED REQUEST WAS MANAGED BY PROCESS pid = 11
# I ASSUME THIS IS WHY IT CREATED A NEW CONNECTION
HARAKIRI: -- syscall> 7 0x7fff4290c6d8 0x1 0xffffffff 0x4000 0x0 0x0
0x7fff4290c6b8 0x7f33d6e3cbc4
HARAKIRI: -- wchan> poll_schedule_timeout
HARAKIRI !!! worker 4 status !!!
HARAKIRI [core 0] - POST /manager/_save_task since 1587660997
HARAKIRI !!! end of worker 4 status !!!
heroku[router]: at=error code=H13 desc="Connection closed without
response" method=POST path="/manager/_save_task"
DAMN ! worker 4 (pid: 11) died, killed by signal 9 :( trying respawn ...
Respawned uWSGI worker 4 (new pid: 14)
# FROM HERE ON, NOTHINGS WORKS ANYMORE
这种行为在多次尝试中是一致的:当 pid 更改时,请求失败。即使在create_engine 函数中使用pool_size = 1,问题仍然存在。没有问题,而是 uwsgi 与一个进程一起使用。
我很确定这是我的错,有些事情我不知道或者我不明白 uwsgi 和/或 sqlalchemy 是如何工作的。你能帮帮我吗?
谢谢
【问题讨论】:
-
嘿,看来你需要在worker之间共享内存。检查这个问题,它没有解决方案,但它确实解释了原因stackoverflow.com/questions/54133550/…。
-
@univerio 我被注册表的唯一 ID 愚弄了。
标签: flask heroku sqlalchemy flask-sqlalchemy uwsgi