首页 > 解决方案 > StreamingHttpResponse:将数据库连接返回到池/关闭它

问题描述

如果你有一个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
  )

如果它有所作为,这是使用带有gunicorn的https://pypi.org/project/django-db-geventpool/,并且任何答案在测试时也应该有效pytest.mark.django_db(我认为在事务中包装测试)

标签: pythondjangopostgresqlpytestgevent

解决方案


如果您查看文档

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

连接管理

Django 在首次进行数据库查询时会打开与数据库的连接。它保持此连接打开并在后续请求中重用它。一旦超过 CONN_MAX_AGE 定义的最大年龄或不再可用时,Django 将关闭连接。

详细地说,当 Django 需要一个连接但还没有连接时,它会自动打开一个到数据库的连接——要么是因为这是第一个连接,要么是因为前一个连接已关闭。

在每个请求开始时,如果连接已达到最大年龄,Django 将关闭连接。如果您的数据库在一段时间后终止空闲连接,您应该将 CONN_MAX_AGE 设置为较低的值,以便 Django 不会尝试使用已被数据库服务器终止的连接。(这个问题可能只影响非常低流量的网站。)

在每个请求结束时,如果连接已达到最大年龄或处于不可恢复的错误状态,Django 将关闭连接。如果在处理请求时发生任何数据库错误,Django 会检查连接是否仍然有效,如果没有则关闭它。因此,数据库错误最多影响一个请求;如果连接变得不可用,下一个请求将获得一个新的连接。

另外,如果您db/__init__.pydjango源代码中看到

# 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)

它连接到request_startedrequest_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
  )

推荐阅读