---
title: "Waiting without blocking"
language: "en"
documentation_version: "3.x"
channel: "development"
release_context: null
source_revision: "10297d1e28653321d6996609fc53718d3b7c8278"
working_tree_clean: true
source_path: "docs/concepts/async.md"
source_sha256: "6ee177706dba8c01a9c7638e01a5a0ff7a5678a99d1e65456fe6a2197e8afd0a"
source_at_revision: true
source_url: "https://github.com/matsumotory/ngx_mruby/blob/10297d1e28653321d6996609fc53718d3b7c8278/docs/concepts/async.md"
html_url: "https://ngx.mruby.org/concepts/async/"
markdown_url: "https://ngx.mruby.org/markdown/concepts/async.md"
last_updated: "2026-10-30"
---

# Waiting without blocking

A worker of nginx serves many connections at once from one event loop. A
handler that waits in a blocking call, such as `sleep` or a socket read,
stops the whole worker. `Nginx::Async.sleep` and
`Nginx::Async::HTTP.sub_request` wait through nginx instead: the Ruby code
of the handler runs in a fiber, which yields to nginx and is resumed from
nginx's event loop.

What happens when an access handler calls `Nginx::Async.sleep`, from the call until the handler's code goes on.

Diagram labels (order does not imply connections):

- call: An access handler's code calls `Nginx::Async.sleep(500)` in its fiber
- timer: `__sleep` adds a timer of 500 ms to nginx's event loop, and `Fiber.yield` suspends the fiber
- done: The handler returns `NGX_DONE`: nginx keeps the request and leaves the handler
- serve: The worker serves its other connections while the timer runs
- fire: The timer fires: `ngx_mrb_timer_handler` resumes the fiber
- resume: The code goes on after `sleep`; when it ends, the request goes on with the next handler, or nginx ends it with the handler's result

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 runs the code of each handler in a fiber of mruby
  (`ngx_mrb_start_fiber`). `Nginx::Async.sleep` arms an nginx timer and
  yields the fiber; while it is suspended, the handler has returned
  `NGX_DONE`, and the worker serves other connections.
- When the timer fires, `ngx_mrb_timer_handler` resumes the fiber with
  the request that it belongs to. If the code ends, ngx_mruby gives nginx
  the result of the handler: the next handler of the phase runs for
  `Nginx::DECLINED`, and nginx ends the request with any other result.
- `Nginx::Async::HTTP.sub_request` works in the same way: it starts an
  nginx subrequest and yields, and nginx resumes the fiber when the
  subrequest has finished.
- `mruby_set` and the post-read, server rewrite, rewrite and access
  handlers can wait and resume. A suspended handler returns `NGX_DONE`,
  or `NGX_AGAIN` while a subrequest continues.
- Since the 2.7.3 changes, also integrated into 3.x, nginx keeps a normal
  content handler's request while `Nginx::Async.sleep` waits. The timer
  resumes the fiber; its response or returned status completes the request.
  Up to released 2.7.2, the request ended at the sleep without a response.
  A content handler reached by `Nginx.redirect` from Ruby still has that
  limitation: the caller continues and can answer the request itself.
- A content handler cannot call `Nginx::Async::HTTP.sub_request` after
  it has waited in `Nginx::Async.sleep`; this raises `RuntimeError`.
  In `mruby_set`, a subrequest does not hold the request: nginx continues
  to the content phase without waiting for the variable. In header/body
  filters and the log handler, both async methods raise `RuntimeError`.
  See [the 2.7.3 behavior changes](/releases/v2.7.3/) and
  [Nginx::Async#sleep](/reference/ruby/#nginxasyncsleepmsec).
- Code that waits in `sleep` of mruby-sleep, a socket of mruby-socket, a
  file, a shell command or a Redis call blocks the worker for that time
  ([Trust boundary](/security/trust-boundary/)).

[Nginx::Async](/reference/ruby/#nginxasync-class) in the
Ruby reference describes both methods.
