Django - Middleware теряет соединение с базой данных в многопользовательском приложении

В моем приложении Django я использую многопользовательский подход с изолированными базами данных. Он работает хорошо, но поскольку он опирается на субдомены для каждого арендатора, что не является масштабируемым, я пытаюсь изменить это. Для достижения этой функциональности я пытаюсь использовать промежуточные модули и сессии для получения арендатора из имени пользователя и использования его для установки локальной переменной для маршрутизаторов базы данных. Логика такова:

Если пользователь не вошел в систему, BeforeLoginMiddleware активируется и получает от пользователя имя арендатора. Таким образом, username@tenant1 установит tenant1 в сессию. Вот код:

import threading
from users.forms import LoginForm

Thread_Local = threading.local()

class BeforeLoginMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):

        if request.path == '/login/':

            form = LoginForm(request.POST)

            if form.is_valid():

                complete_username = form.cleaned_data.get('username')
                current_db = complete_username.split('@')[1]
                request.session['current_db'] = current_db
                request.session.modified = True

        response = self.get_response(request)

        return response

Если пользователь уже вошел в систему, второе промежуточное ПО получит данные арендатора из сессии и использует их для определения переменной Thread_Local, которая вызывается в функции, используемой на маршрутизаторах базы данных:

class AppMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):

        current_db = request.session.get('current_db')
        setattr(Thread_Local, 'current_db', current_db)
        response = self.get_response(request)

        return response

def get_current_db_name():
    return getattr(Thread_Local, 'current_db', None)

Вот файл routers.py:

class AppRouter:

    def db_for_read(self, model, **hints):
        return get_current_db_name()

    def db_for_write(self, model, **hints):
        return get_current_db_name()

    def allow_relation(self, *args, **kwargs):
        return True

    def allow_syncdb(self, *args, **kwargs):
        return None

    def allow_migrate(self, *args, **kwargs):
        return None

Вот настройки промежуточного ПО в моем приложении:

MIDDLEWARE = [
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'myapp.middleware.BeforeLoginMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'myapp.middleware.AppMiddleware',
]

Это работает, как и ожидалось, но в случайных случаях (или, по крайней мере, кажется, что в случайных) он теряет связь с базой данных и, как я предполагаю, поскольку он не может получить данные сессии, снова перенаправляет пользователя на страницу входа (я также использую декоратор login_required). Иногда я могу переходить на несколько разных страниц, и все в порядке, а затем происходит отключение. В других случаях он отключается при переходе на первую страницу после главной, после входа в систему. Это также происходит, если страница простаивает около 1 минуты, что не имеет смысла, потому что мой параметр SESSION_COOKIE_AGE равен 1200.

Дело в том, что я понятия не имею, что вызывает это, потому что нет никаких ошибок. Единственное, что я заметил, когда это происходит, это статус 302, зарегистрированный на вкладке "Сеть" в браузере (который является перенаправлением на страницу входа), и сообщение "Сломанная труба от ('127.0.0.1', 61980) в терминале с этим случайным кодом в конце.

Что я пробовал до сих пор, без каких-либо изменений в поведении, описанном выше:

  • Множество различных настроек для промежуточного ПО. Например: сначала я написал одно промежуточное ПО со всей логикой и поместил его в конец списка промежуточных программ. Я подумал, что это может быть причиной проблемы, поэтому я разделил логику. Другая попытка заключалась в использовании request.user.is_authenticated в промежуточном ПО вместо использования данных сессии.
  • Основываясь на этом ответе, я попытался отключить все JS скрипты в приложения (их всего несколько). Это не совсем выход, но я думаю, что это исключает возможность быть причиной.
  • Полностью очистите кэш/куки браузера.
  • Измените настройку SESSION_SAVE_EVERY_REQUEST на True.
  • Измените значение параметра SESSION_COOKIE_AGE на 120000 (я думаю, что увеличивать это число не имеет смысла, но на данный момент я готов попробовать все).

Честно говоря, у меня уже нет вариантов, поэтому я благодарен за любую помощь или совет.

Вернуться на верх