How can a content handler block on certain events before sending a response?

I’m writing an Nginx module and I’d like to better understand how Nginx
content handlers work and how the Nginx main loop works.

As far as I know, Nginx content handler functions are supposed to create
a chain link of buffers containing the response data, and then call
ngx_http_output_filter(r, &the_chain_link) which will then take care of
passing this data to the next output filter and eventually sending the
data to the HTTP client.

How does one deal with situations in which the content handler function
cannot immediately generate a response? For example, suppose my content
handler must first fetch some data from MySQL. Since Nginx is an evented
server, I imagine that I need to do something like this:

  1. Connect to MySQL and send a request to it.
  2. Register the MySQL client file descriptor on the Nginx main loop.
  3. The Nginx main loop notifies me when the MySQL fd becomes readable.
  4. I read the MySQL response, generate HTTP response data, and call
    ngx_http_output_filter().

But how do I do step 2? Which function do I need to call? What should I
return in my content handler function after having executed step 2?
NGX_AGAIN?

Hello!

On Tue, Nov 23, 2010 at 12:34:31AM +0100, Hongli L. wrote:

cannot immediately generate a response? For example, suppose my content
NGX_AGAIN?
From content handler you should return NGX_DONE to indicate you
are going to send response later. Note that after returing NGX_DONE
you are responsible for finalizing request as well, this should be
done via ngx_http_finalize_request() call.

For an idea how to handle connection, data sending and receiving
please follow upstream module (src/http/ngx_http_upstream.c) and
handlers which use it (e.g. memcached module,
src/http/modules/ngx_http_memcached_module.c).

Working with events isn’t something trivial, but basically you’ll
have to connect via ngx_event_connect_peer(), set up appropriate
read/write handlers in resulting connection structure and call
ngx_handle_(read|write)_event() as appropriate.

Maxim D.

Hi,

For example, suppose my content handler must first fetch some data from
MySQL.

Just take a look at ngx_drizzle :wink:

Best regards,
Piotr S. < [email protected] >

Maxim D. wrote in post #963250:

Working with events isn’t something trivial, but basically you’ll
have to connect via ngx_event_connect_peer(), set up appropriate
read/write handlers in resulting connection structure and call
ngx_handle_(read|write)_event() as appropriate.

I need to use ngx_add_event for registering a read/write watcher, right?
So I need to allocate an ngx_event_s struct, set its ‘handler’ member to
my handler function, and call ngx_add_event(&evt, NGX_READ_EVENT, 0)? Do
I need to set any other members for it to work? Do I need to zero the
structure if I don’t set anything else?

What are appropriate times to call ngx_handle_read/write_event? What do
those functions do? Isn’t the main loop supposed to call event handler
functions for me?

Hello!

On Wed, Nov 24, 2010 at 12:43:46AM +0100, Hongli L. wrote:

Maxim D. wrote in post #963250:

Working with events isn’t something trivial, but basically you’ll
have to connect via ngx_event_connect_peer(), set up appropriate
read/write handlers in resulting connection structure and call
ngx_handle_(read|write)_event() as appropriate.

I need to use ngx_add_event for registering a read/write watcher, right?

No. Depending on event method used there are different things
required, e.g. with epoll and rtsig you have to call
ngx_add_conn() to add connection to the event loop first. And
calling ngx_add_event() isn’t needed (unless you are trying to do
something non-standard or optimize specific case),
ngx_handle_(read|write)_event() will do it for you.

Use ngx_event_connect_peer(), it will handle these details for
you.

So I need to allocate an ngx_event_s struct, set its ‘handler’ member to
my handler function, and call ngx_add_event(&evt, NGX_READ_EVENT, 0)? Do
I need to set any other members for it to work? Do I need to zero the
structure if I don’t set anything else?

See above, use ngx_event_connect_peer().

You may do the same steps by hand but this anyway will require
almost the same code, connection structure and so on.

What are appropriate times to call ngx_handle_read/write_event? What do
those functions do? Isn’t the main loop supposed to call event handler
functions for me?

You should call ngx_handle_(read|write)_event() when you’ve done
processing event (to re-enable this particular event in event
loop, or to disable it if level-triggered event method used and
event is still ready) or when you are going to wait for another
event (to activate particular event in the even loop).

Don’t hesitate to look into event/ngx_event.c. These functions
basically call ngx_add_event/ngx_del_event based on various
conditions depending on event method used.

Maxim D.