---
title: "ブロックせずに待つ"
language: "ja"
documentation_version: "3.x"
channel: "development"
release_context: null
source_revision: "10297d1e28653321d6996609fc53718d3b7c8278"
working_tree_clean: true
source_path: "docs/ja/concepts/async.md"
source_sha256: "07b7916f46b9a275fbec30b574c3dd8d6fd2f20d2aa561ba88f3f9395bb6847e"
source_at_revision: true
source_url: "https://github.com/matsumotory/ngx_mruby/blob/10297d1e28653321d6996609fc53718d3b7c8278/docs/ja/concepts/async.md"
html_url: "https://ngx.mruby.org/ja/concepts/async/"
markdown_url: "https://ngx.mruby.org/markdown/ja/concepts/async.md"
last_updated: "2026-10-30"
---

# ブロックせずに待つ

nginxのワーカーは、1つのイベントループで多くの接続を同時に処理します。`sleep`やソケットの読み込みのような、ブロックする呼び出しでハンドラが待つと、ワーカー全体が止まります。`Nginx::Async.sleep`と`Nginx::Async::HTTP.sub_request`を使うと、ハンドラはnginxを通して待ちます。ハンドラのRubyのコードはファイバーの中で動きます。このファイバーはnginxに制御を返し、nginxがイベントループからそのファイバーを再開します。

accessハンドラが`Nginx::Async.sleep`を呼んでから、ハンドラのコードが先へ進むまでに起きることを示します。

図のラベル（順序は接続を表しません）:

- call: accessハンドラのコードが、ファイバーの中で`Nginx::Async.sleep(500)`を呼ぶ
- timer: `__sleep`がnginxのイベントループに500ミリ秒のタイマーを加え、`Fiber.yield`がファイバーを中断する
- done: ハンドラは`NGX_DONE`を返す。nginxはリクエストを保ったまま、ハンドラを離れる
- serve: タイマーが動いている間、ワーカーはほかの接続を処理する
- fire: タイマーが切れると、`ngx_mrb_timer_handler`がファイバーを再開する
- resume: コードは`sleep`の後から続く。コードが終わると、リクエストは次のハンドラへ進むか、nginxがハンドラの結果でリクエストを終える

Source: ngx_mruby 0c72e3970 (2026-10-19)

- `mrbgems/ngx_mruby_mrblib/mrblib/mrb_nginx.rb`: 100-106
- `src/http/ngx_http_mruby_async.c`: 187-239, 241-314, 316-348, 363-410
- `src/http/ngx_http_mruby_module.c`: 1061-1074
- `src/http/ngx_http_mruby_core.h`: 30-35

- ngx_mrubyは、`ngx_mrb_start_fiber`で、各ハンドラのコードをmrubyのファイバーの中で実行します。`Nginx::Async.sleep`は、nginxのタイマーをセットしてファイバーを中断します。ファイバーが中断している間、ハンドラは既に`NGX_DONE`を返していて、ワーカーはほかの接続を処理します。
- タイマーが切れると、`ngx_mrb_timer_handler`が、ファイバーを、それが属するリクエストとともに再開します。コードが終わると、ngx_mrubyはハンドラの結果をnginxに渡します。結果が`Nginx::DECLINED`ならそのフェーズの次のハンドラが動き、ほかの結果ならnginxはリクエストを終えます。
- `Nginx::Async::HTTP.sub_request`も同じように動きます。このメソッドはnginxのサブリクエストを始めてファイバーを中断し、サブリクエストが終わるとnginxがファイバーを再開します。
- `mruby_set`とpost-read、server rewrite、rewrite、accessのハンドラは待機して再開できます。中断したハンドラは`NGX_DONE`を返し、サブリクエストの処理中は`NGX_AGAIN`を返します。
- 2.7.3の修正以降、通常のcontentハンドラも`Nginx::Async.sleep`で待てます。この修正は3.xにも統合されています。nginxがリクエストを保持し、タイマーでファイバーを再開します。その応答や戻り値のステータスでリクエストが完了します。リリース済みの2.7.2までは、sleepの時点で応答せずに終了していました。
- Rubyの`Nginx.redirect`から呼ばれたcontentハンドラには、sleep時点で終了する制限が残ります。呼び出し元も処理を続け、その場で応答する場合があります。
- contentハンドラで`Nginx::Async.sleep`の待機後に`Nginx::Async::HTTP.sub_request`を呼ぶと、例外は`RuntimeError`。
- `mruby_set`のサブリクエストはリクエストを保持しません。変数の完了を待たず、nginxはcontentフェーズへ進みます。
- ヘッダフィルタ、ボディフィルタ、logハンドラでは、両メソッドが`RuntimeError`を起こします。
- mruby-sleepの`sleep`、mruby-socketのソケット、ファイル、シェルのコマンド、Redisの呼び出しで待つコードは、その間ワーカーをブロックします。詳しくは[信頼境界](/ja/security/trust-boundary/)にあります。

リファレンスの[Nginx::Async](/ja/reference/ruby/#nginxasync-class)に、両方のメソッドの説明があります。

関連する制約の資料：

- [2.7.3の挙動変更](/ja/releases/v2.7.3/)
- [Nginx::Async#sleep](/ja/reference/ruby/#nginxasyncsleepmsec)
