Mojolicious, Async::ORM and DBSlayer

After experimenting with Redis in Mojo (http://github.com/vti/mojox-socket_stream) I wanted to do something asynchronously with DBI also, using my another Async::ORM module. But apparently doing async with DBI is not that easy. By itself DBI blocks everything and thus there are a few workarounds on CPAN with forks, sockets and pipes like AnyEvent::DBI, POE::Component::EasyDBI, POE::Component::SimpleDBI, IO::Lambda::DBI and others. That is why I have AnyEvent::DBI driver inside of Async::ORM. But I wanted to use Mojo::IOLoop as an event loop.

Writing another forking hack module is cool but I am not that smart, that's why I googled with a hope to find some event loop independent async DBI. And I found dbslayer (http://code.nytimes.com/projects/dbslayer/wiki). DBSlayer is a proxy between HTTP+JSON and MySQL. You send your SQL query as a GET request in JSON format and get JSON response. So what I needed is a http client that can send json requests and parse json responses. Mojo has got both.

So I've written DBSlayer driver for Async::ORM that talks to DBSlayer server. Implementation details are not that interesting, but interesting part is in using Mojo::Client and Mojo::JSON.

Start dbslayer server

    dbslayer -c myconf.cnf -s localhost -u foo -x bar

Create an Async::ORM::DBI::DBSlayer handler

    my $client = Mojo::Client->new;
    my $json   = Mojo::JSON->new;

    my $dbh = Async::ORM::DBI::DBSlayer->new(
        database    => 'async_orm',
        json_encode => sub { $json->encode(@_) },
        json_decode => sub { $json->decode(@_) },
        http_req_cb => sub {
            my ($url, $method, $headers, $body, $cb) = @_;

            $url = Mojo::URL->new($url);
            $url->query($body);

            $client->get(
                $url->to_string => sub {
                    my ($self, $tx) = @_;

                    $cb->(
                        $url, $tx->res->code, $tx->res->headers->to_hash,
                        $tx->res->body
                    );
                }
            )->process;
        }
    );

http_req_cb is a callback for making requests to dbslayer server, json_* utilities are for parsing JSON.

Then use it in async Async::ORM manner.

    Article->new(title => 'foo')->create(
        $dbh => sub {
            my ($dbh, $article_) = @_;

        }
    );

This way I can use Mojo::IOLoop (which means in every Mojolicious application) for managing DBI queries inside of Async::ORM!

You can find the latest code at github http://github.com/vti/async-orm/.

Comments

blog comments powered by Disqus