StreamingHttpResponse: вернуть соединение с базой данных в пул / закрыть его - PullRequest
4 голосов
/ 25 апреля 2020

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

def my_view(request):
  # Some database queries using the Django ORM
  # ...

  def yield_data():
    # A generator, with no database queries using the Django ORM
    # ...

  return StreamingHttpResponse(
    yield_data(), status=200
  )

Если это имеет значение, то используется https://pypi.org/project/django-db-geventpool/ с gunicorn, и любой ответ также должен работать при тестировании с pytest.mark.django_db (я думаю, что оборачивает тесты в транзакциях)

1 Ответ

5 голосов
/ 27 апреля 2020

Если вы посмотрите на документацию

https://docs.djangoproject.com/en/3.0/ref/databases/

Управление соединениями

Django открывает соединение с базой данных при первом запросе к базе данных. Это соединение остается открытым и повторно используется в последующих запросах. Django закрывает соединение, когда оно превышает максимальный возраст, определенный CONN_MAX_AGE, или когда оно больше не используется.

Подробно, Django автоматически открывает соединение с базой данных всякий раз, когда оно требуется, и не У него его уже нет - либо потому, что это первое соединение, либо потому, что предыдущее соединение было закрыто.

В начале каждого запроса Django закрывает соединение, если оно достигло максимального возраста. Если через некоторое время ваша база данных завершает неактивные соединения, вам следует установить для CONN_MAX_AGE более низкое значение, чтобы Django не пытался использовать соединение, которое было прервано сервером базы данных. (Эта проблема может затрагивать только очень низкий трафик c сайтов.)

В конце каждого запроса Django закрывает соединение, если оно достигло своего максимального возраста или находится в состоянии неисправимой ошибки , Если при обработке запросов возникли какие-либо ошибки базы данных, Django проверяет, работает ли соединение, и закрывает его, если это не так. Таким образом, ошибки базы данных затрагивают не более одного запроса; если соединение становится непригодным, следующий запрос получает соединение fre sh.

Также, если вы видите db/__init__.py in django исходный код

# For backwards compatibility. Prefer connections['default'] instead.
connection = DefaultConnectionProxy()


# Register an event to reset saved queries when a Django request is started.
def reset_queries(**kwargs):
    for conn in connections.all():
        conn.queries_log.clear()


signals.request_started.connect(reset_queries)


# Register an event to reset transaction state and close connections past
# their lifetime.
def close_old_connections(**kwargs):
    for conn in connections.all():
        conn.close_if_unusable_or_obsolete()


signals.request_started.connect(close_old_connections)
signals.request_finished.connect(close_old_connections)

It имеет соединение с сигналами request_started и request_finished для закрытия старых соединений с использованием close_old_connections.

Поэтому, если вы не хотите ждать закрытия соединений, вы можете вызвать этот метод самостоятельно. Ваш обновленный код будет выглядеть ниже

from django.db import close_old_connections

def my_view(request):
  # Some database queries using the Django ORM
  # ...
  close_old_connections()

  def yield_data():
    # A generator, with no database queries using the Django ORM
    # ...

  return StreamingHttpResponse(
    yield_data(), status=200
  )
...