0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

aiohttp Server でレスポンスを返した後に処理を続ける方法

Last updated at Posted at 2020-05-11

aiohttp で Web サーバを作っていて、HTTP リクエストを受けたら少し重い処理を走らせたい [^job] というとき、そのまま処理を走らせると HTTP レスポンスを返すのが遅くなってしまい、クライアント側でタイムアウトエラーとして処理されてしまうかもしれない。処理結果は返す必要がないとして、いったん HTTP レスポンスを返して HTTP 通信を終わらせて、そのあとで少し重い処理を実行したいときはどうすればいいか。

write_eof する方法

この方法はよくないことがわかったので、追記を参照。

from asyncio import sleep
from aiohttp import web


async def handler(request):
    response = web.Response()
    await response.prepare(request)
    await response.write_eof()

    await sleep(1)  # レスポンスを返したあとの処理


app = web.Application()
app.router.add_get('/', handler)

if __name__ == '__main__':
    web.run_app(app)
Response オブジェクトを作成して `prepare` して `write_eof` すればよい。

Response オブジェクトの作成時に何も指定しなかった場合、HTTP ステータスコードは 200 が返る。

[2020.06 追記] ダメだった

上記方法だと、keep-alive で一定時間コネクションが維持される場合ではたまたま問題なく動いてしまうので気づかなかったが、基本的にうまく動かない。

レスポンスヘッダに Connection: close を追加して keep-alive を無効にしてみると、 write_eof() した時点で以降の非同期処理が実行されないことがわかる。

どうやらクライアントとのコネクションが切断された時点でリクエストハンドラの処理はそこで中止されてしまうようだ。(エラーメッセージも何も出ないので調べるのが大変だった)

参考: https://github.com/aio-libs/aiohttp/issues/4773

解決策としては、aiojobs を使った方が良さそう。

from asyncio import sleep
from aiohttp import web
import aiojobs.aiohttp as aiojobs


async def job():
    """レスポンスを返した後に実行したい処理"""
    await sleep(1)


async def handler(request):
    await aiojobs.spawn(request, job())
    return web.Response(text='ok')


app = web.Application()
app.router.add_get('/', handler)

aiojobs.setup(app)

if __name__ == '__main__':
    web.run_app(app)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?