Flask -sqlalchemy / uwsgi: проблема с подключением к БД при использовании более чем на процессе - PullRequest
0 голосов
/ 23 апреля 2020

У меня на Heroku работает приложение Flask с сервером 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. Не могли бы вы помочь мне?

Спасибо

1 Ответ

1 голос
/ 24 апреля 2020

Что происходит, так это то, что вы пытаетесь разделить память между процессами. В этих сообщениях есть некоторые пояснения.

( возможно ли разделить память между процессами uwsgi, выполняющими flask app? ).

({ ссылка })

Вы можете использовать дополнительный слой для хранения своих сеансов вне приложения.

Для этого вы можете использовать SharedArea uWsgi (https://uwsgi-docs.readthedocs.io/en/latest/SharedArea.html), который является очень низким уровнем, или вы можете использовать другие подходы, такие как кэширование uWsgi (https://uwsgi-docs.readthedocs.io/en/latest/Caching.html)

надеюсь, это поможет.

...