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