Ответ 1
После нескольких недель тестирования и чтения исходного кода Django я нашел ответ на свой вопрос:
Сделки
По умолчанию автозаполнение по умолчанию Django по-прежнему сохраняется для моей потоковой функции. Однако в документах Django указано:
Как только вы выполните действие, которое необходимо записать в базу данных, Django создает инструкции INSERT/UPDATE/DELETE, а затем выполняет COMMIT. Theres не подразумевается ROLLBACK.
Последнее предложение очень буквально. Он НЕ выдает команду ROLLBACK, если только что-то в Django не установило грязный флаг. Поскольку моя функция выполняла только инструкции SELECT, она никогда не устанавливала грязный флаг и не вызывала COMMIT.
Это противоречит факту, что PostgreSQL считает, что транзакция требует ROLLBACK, потому что Django выпустил команду SET для часового пояса. При просмотре журналов я отбросил себя, потому что я продолжал видеть эти инструкции ROLLBACK и предполагал, что управление транзакциями Django является источником. Оказывается, это не так, и это нормально.
Подключения
Управление соединениями - это то, где вещи становятся сложными. Оказывается, Django использует signals.request_finished.connect(close_connection)
для закрытия подключения к базе данных, которое обычно использует. Поскольку в Django обычно не происходит ничего, что не связано с запросом, вы принимаете это поведение как должное.
В моем случае, однако, запроса не было, потому что задание было запланировано. Никакой запрос не означает никакого сигнала. Нет сигнала означает, что соединение с базой данных не было закрыто.
Возвращаясь к транзакциям, выясняется, что простое обращение к connection.close()
при отсутствии каких-либо изменений в управлении транзакциями вызывает оператор ROLLBACK в журнале PostgreSQL, который я искал.
Решение
Решение состоит в том, чтобы позволить нормальному управлению транзакциями Django действовать как обычно и просто закрыть соединение одним из трех способов:
- Напишите декоратор, который закрывает соединение и завершает в нем необходимые функции.
- Захватите существующие сигналы запроса, чтобы Django закрыл соединение.
- Закройте соединение вручную в конце функции.
Любой из этих трех будет (и работает).
Это сбило меня с ума в течение нескольких недель. Надеюсь, это поможет кому-то еще в будущем!