解决方式1:
在处理GET请求时,代码可能会从数据库或其他web资源中获取数据,这些查询可能很慢。 这时候取消查询是最好的: 该连接已经被抛弃了,没有理由再浪费时间和资源(内存等)进行查询,已经没有机会响应了。
不过在POST请求时可能会有些不好,POST请求常常需要将信息存进数据库,不管该连接是否被抛弃了。
预防被取消掉可以用下列几种方法:
使用 asyncio.shield() 来进行存进数据库的处理。
开启一个存入数据库的协程任务。
使用aiojobs或其他第三方库。
async def handler(request):
await asyncio.shield(write_to_redis(request))
await asyncio.shield(write_to_postgres(request))
return web.Response('OK')
解决方式2:
write_to_redis所产生的错误并不能被捕获,这样会导致有很多asyncio的Future异常的日志消息并且是不可恢复的,因为Task被销毁而不是挂起了。
此外,在按照优雅地关闭(Graceful shutdown)中的进行关闭操作时,aiohttp并不会等待这些任务完成,所以你还要找个机会来释放这些重要的数据。
另一方面,aiojobs提供一个生成新任务并且能等待结果(等此类操作)的API。aiojobs会将所有待完成的操作存入内部数据结构中,并且可以优雅地终止这些操作:
from aiojobs.aiohttp import setup, spawn
async def coro(timeout):
await asyncio.sleep(timeout) # do something in background
async def handler(request):
await spawn(request, coro())
return web.Response()
app = web.Application()
setup(app)
app.router.add_get('/', handler)
解决方式3:
所有未完成的任务会被终止并由aiohttp.web.Application.on_cleanup信号发送出去。
使用@atomic装饰器可以使整个处理器都防止有取消操作:
from aiojobs.aiohttp import atomic
@atomic
async def handler(request):
await write_to_db()
return web.Response()
app = web.Application()
setup(app)
app.router.add_post('/', handler)
解决 asyncio的Future异常的日志消息并且是不可恢复的,因为Task被销毁而不是挂起了
最新推荐文章于 2024-09-14 22:43:30 发布