Friday, October 16, 2009

Event driven PSGI

I spent most of today and yesterday bikeshedding event driven PSGI with miyagawa on #http-engine.

We seem to have converged on something that is both fairly portable to different event driven implementations, without being too yucky for blocking backends.

For example, if you don't yet know the response code or headers and are waiting on some other event driven thing, it's sort of like continuation passing style:

$app = sub {
    my $env = shift;

    ...

    return sub {
        my $write = shift;

        $some_event_thingy->do_your_thing( when_finished => sub {
            $write->([ 200, $headers, $body ]);
        });
    };
};

A more complex example involves streaming:

$app = sub {
    my $env = shift;

    ...

    return sub {
        my $write = shift;

        my $out = $write->([ 200, $headers ]);

        $some_event_thingy->new_data(sub {
            my $data = shift;

            if ( defined $data ) {
                $out->write($data);
            } else {
                $out->close;
            }
        });
    };
};

Lastly, if you are worried about too much memory usage in the output buffer, you can provide a callback to poll_cb:

$app = sub {
    my $env = shift;

    ...

    return sub {
        my $write = shift;

        $write->([ 200, $headers ])->poll_cb(sub {
            my $out = shift;

            $out->write($some_more);

            $out->close() if $finished;
 });
    };
};

But poll_cb should only be used on event driven backends (check for it using $out->can("poll_cb")).

This lets simple streaming applications will work nicely under blocking backends as well as event driven ones.

Even better, while I was busy implementing this this for the AnyEvent backend frodwith whipped up a POE implementation in no time at all.

This pretty much obsoletes my IO::Writer sketch. The only case it doesn't cover but which IO::Writer theoretically does is poll_cb based nonblocking output, combined with a non blocking data source, but without an event driven environment. This sucks because nonblocking IO without an event loop wastes a lot of CPU. I can't imagine why anyone would actually try that, so I hereby declare IO::Writer deprecated, thankfully before I actually wrote a robust implementation ;-)

3 comments:

Dana said...

As always, a mind-expanding post. Thanks so much and continue the good research!

hdp said...

You two were talking about this forever today, so I'm glad you came to a simple and satisfying conclusion. Good work.

miyagawa said...

Yay, i blogged mine here:
http://bulknews.typepad.com/blog/2009/10/psgiplack-streaming-is-now-complete.html