我有一个Flask应用在Heroku上运行,有uwsgi服务器,其中每个用户都连接到自己的数据库。我已经实现了 类似情况的解决方案. 特别是,我实现了如下的连接注册表。
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改变时,请求失败。即使有一个 pool_size = 1
在 create_engine
函数,问题依然存在。没有问题,反而是uwsgi被用在一个进程上。
我很确定这是我的错,有一些我不知道的东西,或者我不了解uwsgi和sqlalchemy的工作方式。你能不能帮帮我?
谢谢你的帮助
遇到的情况是你正在尝试在进程之间共享内存,这些帖子中有一些解释。
(是否可以在运行flask应用的uwsgi进程之间共享内存?).
(https:/stackoverflow.coma4538361711542053。)
你可以使用一个额外的层来存储你在应用程序之外的会话。
为此,你可以使用 uWsgi 的 SharedArea(https:/uwsgi-docs.readthedocs.ioenlatestSharedArea.html。),这是非常低级的,或者你可以使用其他方法,比如uWsgi的缓存(https:/uwsgi-docs.readthedocs.ioenlatestCaching.html。)
希望对你有所帮助。