首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有websockets的uvicorn starlette应用程序的优雅关闭

具有websockets的uvicorn starlette应用程序的优雅关闭
EN

Stack Overflow用户
提问于 2019-09-27 11:30:20
回答 2查看 8.1K关注 0票数 17

考虑到这个带有开放websocket连接的示例Starlette应用程序,您如何关闭Starlette应用程序?我在运行uvicorn。每当我按Ctrl+C时,输出就是Waiting for background tasks to complete.,它永远挂起。

代码语言:javascript
复制
from starlette.applications import Starlette

app = Starlette()

@app.websocket_route('/ws')
async def ws(websocket):
    await websocket.accept()

    while True:
        # How to interrupt this while loop on the shutdown event?
        await asyncio.sleep(0.1)

    await websocket.close()

我尝试在关机事件上切换bool变量,但是变量从未更新。它永远是False

例如:

代码语言:javascript
复制
app.state.is_shutting_down = False


@app.on_event('shutdown')
async def shutdown():
    app.state.is_shutting_down = True


@app.websocket_route('/ws')
async def ws(websocket):
    await websocket.accept()

    while app.state.is_shutting_down is False:
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-23 21:08:55

变量未发生更改的原因是“关机”事件的处理程序在执行所有任务后执行(即,当关闭处理程序等待异步任务和异步任务等待关闭处理程序时,我们将陷入死锁)。

在异步事件循环上设置一个信号处理程序可能无法工作,因为我认为只允许一个信号处理程序,而uvicorn已经为它自己的关闭过程设置了这个处理程序。

相反,您可以通过Monkey修补uvicorn信号处理程序来检测应用程序关闭,并在该新函数中设置控制变量。

代码语言:javascript
复制
import asyncio
from starlette.applications import Starlette
from uvicorn.main import Server

original_handler = Server.handle_exit

class AppStatus:
    should_exit = False
    
    @staticmethod
    def handle_exit(*args, **kwargs):
        AppStatus.should_exit = True
        original_handler(*args, **kwargs)

Server.handle_exit = AppStatus.handle_exit

app = Starlette()

@app.websocket_route('/ws')
async def ws(websocket):
    await websocket.accept()

    while AppStatus.should_exit is False:
        
        await asyncio.sleep(0.1)

    await websocket.close()
    print('Exited!')
票数 13
EN

Stack Overflow用户

发布于 2019-11-28 13:23:30

我真的不能重现这个问题,我得到

代码语言:javascript
复制
INFO: Started server process [31]
INFO: Waiting for application startup.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
^CINFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Finished server process [31]

但是,在我自己的异步应用程序中,我要优雅地关闭的是:

代码语言:javascript
复制
import signal

async def shutdown(signal: signal):
    """
    try to shut down gracefully
    """
    logger.info("Received exit signal %s...", signal.name)
    tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
    [task.cancel() for task in tasks]
    logging.info("Canceling outstanding tasks")
    await asyncio.gather(*tasks)


if __name__ == "__main__":

    loop = asyncio.get_event_loop()
    signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT)
    for s in signals:
        loop.add_signal_handler(
            s, lambda s=s: asyncio.create_task(shutdown(s))
        )

您可能必须将await websocket.close()移动到shutdown方法中。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58133694

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档