[mod_wsgi] asynchronous extensions

Hi.

Its time to add asynchronous extensions to the WSGI module.

I’m developing a WSGI application where I need to talk with a web
service on the Internet, so it is very important to use an
asynchronous HTTP client.

I have choose libcurl, since it is well designed and there is a wrapper
for Python.

Here is what I’m thinking to do:

  1. when libcurl creates a socket, I create an associated nginx
    connection, by calling the ngx_get_connection function

  2. when I need a read notifycation, I call ngx_handle_read_event

  3. when I need a read notifycation, I call ngx_handle_write_event

  4. when I’m done with libcurl, I call ngx_close_connection

Of course I have to setup the timeouts, but is this all I need to do?
The event structure has a lot of members, and I’m not sure to understand
all of them.

Also, there is a problem with ngx_close_connetion: it will close the
socket, but the socket is owned by libcurl, so I will need to patch it.

Thanks Manlio P.

Manlio P. ha scritto:

Hi.

Its time to add asynchronous extensions to the WSGI module.

I’m developing a WSGI application where I need to talk with a web
service on the Internet, so it is very important to use an
asynchronous HTTP client.

[…]

Some more detailed questions:

  1. Can I use NGX_READ_EVENT and NGX_WRITE_EVENT as bit masks?
    As an example:
    flags = NGX_READ_EVENT | NGX_WRITE_EVENT
    if (flags & NGX_READ_EVENT) {…}

  2. What’s the meaning of active, disabled, ready and oneshot attributes
    in the event structure?

    And what about the write attribute?

  3. Should I set event->ready = 0 after I have handled an event?
    Are there other things that I need to do in the event handler?
    Note that I do not need to write or read from the socket.

  4. The handle_write_event function remove the event when
    wev->active && wev->ready.

    What’s the rationale?

  5. It seems that the event module does not allow me to register an
    event for both read and write notifications.

    This can be a problem for me, since I have to manage two
    callbacks…
    I have to check.

    Moreover there is a difference in how events are handled in the
    select and poll module, as an example.

    For the select module it is the passed in event object that is
    posted, and I have no way to know if the socket is ready for reading
    or writing.

    With the poll module it is the event->data->read and/or
    event->data->write that is posted.

    What’s the rationale?
    I’m not an expert, but why the select module does not do the same as
    the poll module?

  6. The event module assumes that the event data is the connection
    structure.
    What should I do if I need to keep more data?

    As an example, in my case I need to store the peer connection but
    also the http request.

Thanks Manlio P.

Manlio P. ha scritto:

select and poll module, as an example.
the poll module?

Ok, forget this ;-).

For adding both read and write events I have only to call add_event two
times, or just use the handle_read_event and handle_write_event
functions.

There is still the problem of having to handle read and write events
separately:

curl_multi_socket_action
(curl_multi_socket)
can handle both read and write event in one call.

Thanks Manlio P.

Igor S. ha scritto:

[…]

[…]
Next answers later.

Igor, thanks for the documentation!

I have solved most of the problems, and I have a working draft.

However I have found a problem, and unfortunately I’m not expert of
epoll internals.

As I have written, I’m using libcurl as the HTTP client.

Here is the operations I do:

  1. libcurl tells me that it is waiting for the socket to be writeable,
    and I call handle_write_event(self->c->write, 0)

    Since this is the first time that I see the socket I call
    ngx_get_connection and after this I call ngx_add_conn (if defined)

  2. libcurl tells me to deregister the socket, and I call
    ngx_del_event(self->c->write, NGX_WRITE_EVENT, 0)

  3. libcurl tells me that it is waiting for the socket to be readable,
    and I call ngx_handle_read_event(self->c->read, 0),
    but I get an error:
    epoll_ctl(EPOLL_CTL_ADD, 8) failed (17: File exists)

What I’m doing wrong?

Thanks Manlio P.

On Tue, Mar 04, 2008 at 01:30:07PM +0100, Manlio P. wrote:

Some more detailed questions:

  1. Can I use NGX_READ_EVENT and NGX_WRITE_EVENT as bit masks?
    As an example:
    flags = NGX_READ_EVENT | NGX_WRITE_EVENT
    if (flags & NGX_READ_EVENT) {…}

No, they can not ORed at least in kqueue method.

  1. What’s the meaning of active, disabled, ready and oneshot attributes
    in the event structure?

    And what about the write attribute?

/*
 * the event was passed or would be passed to a kernel;
 * in aio mode - operation was posted.
 */
unsigned         active:1;

/* the ready event; in aio mode 0 means that no operation can be 

posted */
unsigned ready:1;

disabled: event filter has been allocated in kernel, but disabled 

now.
The optimization that allows to avoid lock aquiring in
kernel
allocation.

oneshot: event filter is oneshot, Solaris event port, kqueue's 

EV_ONESHOT,
epoll’s EPOLLONESHOT.

write: write event filter (NGX_WRITE_EVENT).

Next answers later.