Django повторно подключается к базе данных при потере соединения

У меня есть проект django, база данных Mysql находится на отдельном хосте, подключенном по протоколу TCP. У меня есть этот скрипт:

#!/usr/bin/env python

from asyncio import sleep, run

from django import setup as django_setup
django_setup()

from django.db import connections
from django.contrib.auth.models import User
from django.db import OperationalError, close_old_connections

async def test():
    while True:
        try:
            objs=User.objects.all()
            print(await objs.acount())
        except KeyboardInterrupt:
            break
        except OperationalError as e: # Need to reconnect
            print(f'main(): OperationalError: {e}')
            #raise
            # (1053, 'Server shutdown in progress')
            # (2013, 'Lost connection to MySQL server during query')
            # (2006, 'Server has gone away')
            code=e.args[0]
            if code in {1053, 2006, 2013, 2026}: # Only when it's restarting, and once
                #await sync_to_async(conn.connect)()
                close_old_connections()
                print('After reconnect')
                #reconnect()
            else:
                #breakpoint()
                pass
        except Exception as e:
            print(f'in _round() {type(e)}')
        else:
            pass
            #breakpoint()

        print('Sleeping')
        await sleep(5)

try:
    run(test())
except KeyboardInterrupt:
    raise
except:
    print('In run(main())')
    breakpoint()
    pass

Затем я использую tcpkill, чтобы прервать соединение:

tcpkill 'dst port 3306'

Как мне дать команду django на повторное подключение? Я не делаю это автоматически, close_old_connection не работает, результат выглядит следующим образом:

3
Sleeping
3
Sleeping
main(): OperationalError: (2013, 'Lost connection to MySQL server during query')
After reconnect
Sleeping
main(): OperationalError: (2013, 'Lost connection to MySQL server during query')
After reconnect
Sleeping
main(): OperationalError: (2013, 'Lost connection to MySQL server during query')
After reconnect
Sleeping

При просмотре кода я вижу, что он порождает объект курсора из объекта подключения, но не работает, а затем закрывается, в то время как, вероятно, объект подключения остается нетронутым и продолжает выдавать непригодные для использования курсоры. Я пробовал connection.connect(), но это не сработает, потому что код асинхронный.

Вы можете сделать это с помощью промежуточного программного обеспечения, я полагаю, если этот вопрос связан с пользователями, фактически использующими ваше приложение.

from django.db import connection, OperationalError
from django.utils.deprecation import MiddlewareMixin

class ReconnectMiddleware(MiddlewareMixin):
    def process_request(self, request):
        try:
            # test the connection
            connection.cursor()
        except OperationalError:
            # if not close and next time 
            # view hits it will try to reconnect
            connection.close()

Теперь добавьте промежуточное программное обеспечение к вашему settings.py (Вероятно, превыше всего остального)

MIDDLEWARE = [
 '[wherever].ReconnectMiddleware',
 # others...
]

Это приводит к тому, что при каждом просмотре вы нажимаете на это промежуточное программное обеспечение. Оно проверяет или закрывает соединение. Так, например, если ваша база данных теряет соединение, а затем вы загружаете страницу и возникает эта ошибка, при следующей загрузке страницы (если база данных доступна) она снова подключится.

функция close_old_connections() не работает, потому что в асинхронном режиме все объекты будут находиться в разных потоках. И, вероятно, я вызывал ее по-другому, когда connect в sync_to_sync не работал. Итак, в конце концов, это работает:

await sync_to_async(reconnect)()

с помощью этой функции:

def reconnect():
    conn=connections['default']
    conn.connect()
Вернуться на верх