StreamingHttpResponse:将数据库连接返回到池/关闭它

Mic*_*mza 4 python django postgresql pytest gevent

如果您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
  )
Run Code Online (Sandbox Code Playgroud)

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

Tar*_*ani 5

如果您查看文档

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)
Run Code Online (Sandbox Code Playgroud)

它具有与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
  )
Run Code Online (Sandbox Code Playgroud)