Сеансы Django периодически завершаются неудачей

В прошлом году я написал приложение для общественного мероприятия, которое я провожу, под названием Nashville Tabletop Day. Приложение позволяет людям сканировать QR-коды, чтобы взаимодействовать с играми, в которые они могут играть в течение дня. На местном уровне оно работает отлично. Однако когда я отправляю его на Fly.io, оно работает, но постоянно сбрасывает сеансы. То есть я могу войти в систему, просмотреть страницу или две, а затем сессия просто исчезает. Это происходит даже если я остаюсь на одной и той же странице и просто перезагружаюсь несколько раз.

Это происходит не сразу, иначе я бы подумал, что, возможно, проблема в базе данных. Но через 15-30 секунд или несколько загрузок страницы - и все. Мероприятие состоится в ближайшую субботу, и это приложение должно быть готово к работе.

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

Django 4.1.7
Python 3.8.18
Database is SQLite

INSTALLED_APPS = [
    'ntd.apps.NtdConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'whitenoise.runserver_nostatic',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'ntd.middleware.request_logger.RequestLoggerMiddleware',
]

Некоторые отладки, которые я сделал:

Я добавил простую промежуточную программу для ведения журнала и вывел request.session.session_key и request.path. Локально при каждой перезагрузке выводится attendee_uuid (значение, которое меня интересует) и два других значения. Когда я передаю этот код во Fly, все три значения выводятся несколько раз, а затем начинает выводиться None.

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

Немного дополнительной информации: Я только что заметил, что админ Django также выводит меня из системы.

Значит, проблема точно в сессии. Пожалуйста, помогите!

Проблема заключается в том, что fly.io автоматически масштабирует приложение по горизонтали и размещает его за своим балансировщиком нагрузки.

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

Долгосрочным решением является использование единой базы данных для всех экземпляров вашего приложения; я бы предложил Fly Postgress, но fly.io дает довольно полный обзор вариантов здесь.

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

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