Были ли сложности с синхронизацией данных при синхронных запросах
Что проверяют
Сталкивались ли вы с конкурентным доступом к данным на бэкенде и понимаете ли, где на самом деле возникает гонка. В синхронном Django или Flask под gunicorn запросы обрабатываются параллельно несколькими процессами, и два одновременных запроса легко затирают изменения друг друга. Следом спросят, почему threading.Lock тут не помог бы.
Как отвечать
Возьмите реальный случай и расскажите по шагам: что сломалось, как нашли, как починили. Типовые сюжеты:
- потерянное обновление: прочитали баланс в Python, вычли, сохранили. Решение: атомарный
UPDATEна стороне базы, в Django черезF("balance") - amount, либоselect_for_update()внутриtransaction.atomic(); - гонка при создании: два запроса одновременно делают
get_or_createи получают дубль илиIntegrityError. Спасает уникальный индекс в базе и обработка исключения, а не проверка в коде; - оптимистическая блокировка: колонка
versionиUPDATE ... WHERE id = %s AND version = %s, при нуле обновлённых строк повтор или ошибка пользователю; - внешний вызов внутри транзакции: синхронный
requests.postк платёжке держит блокировку строки секундами, остальные запросы ждут. Вызов выносят за транзакцию или в Celery, согласованность держат через outbox и ключи идемпотентности; - кэш и база: после записи в Redis остаётся старое значение. Инвалидируют после коммита через
transaction.on_commit.
Упомяните изоляцию: в PostgreSQL по умолчанию Read Committed, и от потерянного обновления он сам не защищает.
Детали нужны ваши: объём, как воспроизвели гонку, как проверили исправление. Если с таким не сталкивались, скажите честно и разберите, как нашли бы и воспроизвели гонку нагрузочным тестом.
Где спотыкаются
Предлагают threading.Lock или глобальную переменную. Под gunicorn с несколькими воркерами это разные процессы, и блокировка в памяти одного остальным не видна.
Надеются на GIL. Он не делает атомарной последовательность «прочитать, изменить, записать» ни в памяти, ни тем более в базе.
Тянут распределённую блокировку в Redis туда, где хватило бы атомарного UPDATE или SELECT ... FOR UPDATE. Лишний компонент приносит новые отказы.