Django(不提供 ASGI 服务器)不限制事件循环的生命周期。
在这个问题的情况下:
- ASGI 服务器:Uvicorn
- 事件循环:内置 asyncio 事件循环或
uvloop(均不限制其生命周期)
对于 Uvicorn:
-
事件循环的生命周期有多长?
事件循环的生命周期与工作线程的生命周期一样长。
-
有超时吗?
不,任务一直运行到完成(除非工作人员没有响应并被 Gunicorn 杀死)。
-
它取决于什么?在 Uvicorn 上?
Worker 的生命周期主要受限于--limit-max-requests(Gunicorn:--max-requests)。
-
这是可配置的吗?
是的,但工人仍然会在某个时候退出。它也可能因其他原因被杀死。
通过指定--limit-max-requests 2 并运行两次视图来亲自查看问题:
uvicorn mysite.asgi:application --limit-max-requests 2
优雅关机
不管生命周期如何限制,我们可能关心的是如何处理关机。
Uvicorn 如何优雅关机?
让我们看看 Uvicorn worker (uvicorn.server.Server) 是如何优雅关闭请求的。
uvicorn.protocols.http.h11_impl.H11Protocol#__init__:存储对服务器任务的引用
# Shared server state
self.server_state = server_state
self.tasks = server_state.tasks
uvicorn.protocols.http.h11_impl.H11Protocol#handle_events:将请求任务添加到任务中
self.cycle = RequestResponseCycle(
...
)
task = self.loop.create_task(self.cycle.run_asgi(app))
task.add_done_callback(self.tasks.discard)
self.tasks.add(task)
uvicorn.server.Server#shutdown:等待现有任务完成
if self.server_state.tasks and not self.force_exit:
msg = "Waiting for background tasks to complete. (CTRL+C to force quit)"
logger.info(msg)
while self.server_state.tasks and not self.force_exit:
await asyncio.sleep(0.1)
如何让 Uvicorn worker 等待你的任务?
让我们通过将您的任务添加到服务器任务来搭载它。
async def async_view(request):
loop = asyncio.get_event_loop()
# loop.create_task(http_call_async()) # Replace this
task = loop.create_task(http_call_async()) # with this
server_state = await get_server_state() # Add this
task.add_done_callback(server_state.tasks.discard) # Add this
server_state.tasks.add(task) # Add this
return HttpResponse("Non-blocking HTTP request")
import gc
from uvicorn.server import ServerState
_server_state = None
@sync_to_async
def get_server_state():
global _server_state
if not _server_state:
objects = gc.get_objects()
_server_state = next(o for o in objects if isinstance(o, ServerState))
return _server_state
现在,Uvicorn 工作人员将在正常关机中等待您的任务。