python - 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
(我认为在事务中包装测试)
解决方案
如果您查看文档
https://docs.djangoproject.com/en/3.0/ref/databases/
连接管理
Django 在首次进行数据库查询时会打开与数据库的连接。它保持此连接打开并在后续请求中重用它。一旦超过 CONN_MAX_AGE 定义的最大年龄或不再可用时,Django 将关闭连接。
详细地说,当 Django 需要一个连接但还没有连接时,它会自动打开一个到数据库的连接——要么是因为这是第一个连接,要么是因为前一个连接已关闭。
在每个请求开始时,如果连接已达到最大年龄,Django 将关闭连接。如果您的数据库在一段时间后终止空闲连接,您应该将 CONN_MAX_AGE 设置为较低的值,以便 Django 不会尝试使用已被数据库服务器终止的连接。(这个问题可能只影响非常低流量的网站。)
在每个请求结束时,如果连接已达到最大年龄或处于不可恢复的错误状态,Django 将关闭连接。如果在处理请求时发生任何数据库错误,Django 会检查连接是否仍然有效,如果没有则关闭它。因此,数据库错误最多影响一个请求;如果连接变得不可用,下一个请求将获得一个新的连接。
另外,如果您db/__init__.py
在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)
它连接到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
)
推荐阅读
- angular - 更新后 Angular 8 订阅触发
- java - 不使用框架管理 DI 对象
- vfs - 如何在块设备层考虑 VFS 操作?
- angular - Angular:如何用实时 api 替换硬编码对象?
- c# - 为什么 AES 加密的结果在使用 C# 和使用 OpenSSL C++ 之间存在巨大差异?
- javascript - peer-peer 没有在所有浏览器中使用 peerJS 连接
- c++ - 如何阻止英特尔 icpc 抱怨对 basic_string 的未定义引用?
- python-3.x - Python3子进程:获取8位以上的进程返回码
- android - 使用超过 25 个航点/坐标的 MapBox 绘制路线/折线
- git - 为什么 Git 子树一遍又一遍地处理相同的提交?