Flask sqlalchemy/uwsgi:使用多个进程时出现DB连接问题

Flask sqlalchemy/uwsgi:使用多个进程时出现DB连接问题,flask,heroku,sqlalchemy,flask-sqlalchemy,uwsgi,Flask,Heroku,Sqlalchemy,Flask Sqlalchemy,Uwsgi,我有一个Flask应用程序在Heroku上运行,带有uwsgi服务器,其中每个用户都连接到自己的数据库。我已经实施了这个计划。特别是,我实现了连接注册表,如下所示: class DBSessionRegistry(): _registry = {} def get(self, URI, **kwargs): if URI not in self._registry: current_app.logger.info(f'INFO - CRE

我有一个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()
无论何时我需要与DB通话,我都会打电话:

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=12处理的所有以前的请求
utils中的信息:会话ID:139860361716304
utils中的信息:注册表ID:139860484608480
utils中的信息:注册表大小:1
utils中的信息:应用程序ID:139860526857584
#注意下一行中的pid。。。
[pid:12 |应用程序:0 |请求:1/1]POST/manager/_save_task=>
在3457毫秒内生成154字节(HTTP/1.1200)在601中生成4个标头
字节(核心0上的1个开关)
#上一个请求由进程pid=12管理
#下一个请求来自同一个用户和同一个URL。
#所以不需要创建新连接,而是。。。
信息-创建新连接
#在这一点上,我不明白为什么它创建了一个新的连接。
#会话ID会更改,因为它是一个新会话
utils中的信息:会话ID:139860363793168#轮询#计划#超时
哈拉基里!!!工人4状态!!!
HARAKIRI[core 0]-自158760997年以来的POST/manager/_save_任务
哈拉基里!!!工人4状态结束!!!
heroku[router]:at=错误代码=H13 desc=“连接已关闭,但未关闭”
响应“method=POST path=“/manager/\u save\u task”
该死工人4(pid:11)死亡,被信号9:(试图重生。。。
新生的uWSGI工人4(新pid:14)
#从现在起,一切都不起作用了
此行为在多次尝试中都是一致的:当pid更改时,请求失败。即使在
create\u engine
函数中使用
pool\u size=1
,问题仍然存在。没有问题的是,uwsgi与一个进程一起使用

我很确定这是我的错,关于uwsgi和/或sqlalchemy是如何工作的,有些事情我不知道或不理解。你能帮我吗


谢谢

问题是您试图在进程之间共享内存。 这些职位上有一些考试

()

()

您可以使用一个额外的层来存储应用程序外部的会话

为此,您可以使用uWsgi的SharedArea(),它的级别非常低,也可以使用其他方法,如uWsgi的caching()


希望有帮助。

嘿,似乎你需要在工作人员之间共享内存。检查这个问题,它没有解决方案,但它确实解释了原因。@univerio我被注册表的唯一id愚弄了。谢谢,我尝试过使用惰性应用程序,所以每个进程都以“自己的应用程序”开始(我在日志消息中看到应用程序为每个进程启动,并且我有不同的当前应用程序ID)。但是,问题仍然存在,但为什么?在这种情况下,应用程序不是独立的吗?发生这种情况的原因是你的应用程序是独立的。如果你第一次提出请求,并且请求由worker1处理,那么它将在worker1的应用程序上创建一个会话,如果你的第二个请求由worker2处理,并且没有访问worker1数据的权限,那么你将被释放吃另一个会话,这次是worker2。我理解多个进程和一个应用程序之间的冲突(就像我最初的情况一样),但对于lazy_应用程序,我们有不同的进程-->不同的应用程序-->不同的注册表-->不同的会话,因此在这里这应该不是问题,因为没有会话共享,并且数据在数据库中。是否关闭会话?我经常遇到这种问题。似乎死锁正在出现。