Re: AnyEvent::DBI + Apache + Plack
User:
mcholste
Date: 12/3/2011 3:33 pm
Date: 12/3/2011 3:33 pm
Views: 453
Rating: 0
Rating: 0
Ok, nevermind Rob, it does indeed work. The trick is that you need a
separate new DBH for every concurrent query so they have a different
file descriptor. Here's the proof-of-concept code:
#!/usr/bin/perl
use strict;
use Data::Dumper;
use DBI;
use AnyEvent;
my %ret;
my %watchers;
my $cv = AnyEvent->condvar;
$cv->begin(sub { shift->send; });
my $db_params = [ 'dbi:mysql:database=test', 'root', '', { RaiseError => 1 } ];
# This query sleeps 3 seconds
async_query(1, $db_params, 'SELECT SLEEP(3), 1', $cv, \%ret, \%watchers);
# This query sleeps 5 seconds
async_query(2, $db_params, 'SELECT SLEEP(5), 2', $cv, \%ret, \%watchers);
$cv->end;
$cv->recv;
# We don't get here until both queries are done
print "Done!\n";
print Dumper(\%ret);
sub async_query {
my $id = shift;
my $dbh_args = shift;
my $query = shift;
my $cv = shift;
my $ret = shift;
my $watchers = shift;
$cv->begin;
my $dbh = DBI->connect(@$dbh_args) or die($DBI::errstr);
my $sth = $dbh->prepare($query, { async => 1 });
$sth->execute;
print "Executing query $query\n";
$watchers{$id} = AnyEvent->io( fh => $dbh->mysql_fd, poll =>
'r', cb => sub {
print "MySQL result for query $query\n";
$ret->{$id} = $sth->fetchall_arrayref;
$cv->end;
print "Got result for query $query\n";
});
}
On Sat, Dec 3, 2011 at 2:52 PM, Martin Holste wrote:
> Hm, ok, but here's a second wrinkle: if you have any
> AnyEvent->condvar->recv calls in your code, you can't run it under an
> AnyEvent-based HTTP server like Twiggy or Feersum because of recursive
> blocking recv calls.
>
> Rob, have you used your MySQL async interface with AnyEvent in such a
> way that you wait until parallelized SQL calls to different servers
> are all in before proceeding? It seems theoretically feasible to me
> if you wrap the async calls in an AnyEvent sub, but I could see how it
> might not be possible given that you need to use the condvar. That
> would allow the parallel MySQL calls without having to use
> AnyEvent::DBI, which forks and creates the Apache problems.
>
> On Fri, Dec 2, 2011 at 5:11 PM, wrote:
>> jt wrote:
>>
>> The general rule is that you only use AnyEvent stuff inside of non-forking
>> servers such as Feersum (https://github.com/stash/Feersum). And then proxy
>> with Apache or nginx or whatever.
>>
>>
>>
>> On Dec 2, 2011, at 4:01 PM, wrote:
>>
>> mcholste wrote:
>>
>> I'm having a really tough time getting AnyEvent::DBI working correctly
>> under Apache. The problem is that the parent process in Apache never
>> goes away, which leaves the child forks of AnyEvent::DBI running and
>> consuming memory. A workaround is to forcefully ->DESTROY the DBH as
>> soon as it's done being used, but that leaves some zombies around for
>> awhile and produces a ton of warnings. Anyone dealt with this kind of
>> thing before?
>>
>> View Online
>>
>>
>>
>> Madison Area Perl Mongers - MadMongers
>> http://www.madmongers.org
>>
>>
>> View Online
>>
>>
>>
>> Madison Area Perl Mongers - MadMongers
>> http://www.madmongers.org
separate new DBH for every concurrent query so they have a different
file descriptor. Here's the proof-of-concept code:
#!/usr/bin/perl
use strict;
use Data::Dumper;
use DBI;
use AnyEvent;
my %ret;
my %watchers;
my $cv = AnyEvent->condvar;
$cv->begin(sub { shift->send; });
my $db_params = [ 'dbi:mysql:database=test', 'root', '', { RaiseError => 1 } ];
# This query sleeps 3 seconds
async_query(1, $db_params, 'SELECT SLEEP(3), 1', $cv, \%ret, \%watchers);
# This query sleeps 5 seconds
async_query(2, $db_params, 'SELECT SLEEP(5), 2', $cv, \%ret, \%watchers);
$cv->end;
$cv->recv;
# We don't get here until both queries are done
print "Done!\n";
print Dumper(\%ret);
sub async_query {
my $id = shift;
my $dbh_args = shift;
my $query = shift;
my $cv = shift;
my $ret = shift;
my $watchers = shift;
$cv->begin;
my $dbh = DBI->connect(@$dbh_args) or die($DBI::errstr);
my $sth = $dbh->prepare($query, { async => 1 });
$sth->execute;
print "Executing query $query\n";
$watchers{$id} = AnyEvent->io( fh => $dbh->mysql_fd, poll =>
'r', cb => sub {
print "MySQL result for query $query\n";
$ret->{$id} = $sth->fetchall_arrayref;
$cv->end;
print "Got result for query $query\n";
});
}
On Sat, Dec 3, 2011 at 2:52 PM, Martin Holste wrote:
> Hm, ok, but here's a second wrinkle: if you have any
> AnyEvent->condvar->recv calls in your code, you can't run it under an
> AnyEvent-based HTTP server like Twiggy or Feersum because of recursive
> blocking recv calls.
>
> Rob, have you used your MySQL async interface with AnyEvent in such a
> way that you wait until parallelized SQL calls to different servers
> are all in before proceeding? It seems theoretically feasible to me
> if you wrap the async calls in an AnyEvent sub, but I could see how it
> might not be possible given that you need to use the condvar. That
> would allow the parallel MySQL calls without having to use
> AnyEvent::DBI, which forks and creates the Apache problems.
>
> On Fri, Dec 2, 2011 at 5:11 PM, wrote:
>> jt wrote:
>>
>> The general rule is that you only use AnyEvent stuff inside of non-forking
>> servers such as Feersum (https://github.com/stash/Feersum). And then proxy
>> with Apache or nginx or whatever.
>>
>>
>>
>> On Dec 2, 2011, at 4:01 PM, wrote:
>>
>> mcholste wrote:
>>
>> I'm having a really tough time getting AnyEvent::DBI working correctly
>> under Apache. The problem is that the parent process in Apache never
>> goes away, which leaves the child forks of AnyEvent::DBI running and
>> consuming memory. A workaround is to forcefully ->DESTROY the DBH as
>> soon as it's done being used, but that leaves some zombies around for
>> awhile and produces a ton of warnings. Anyone dealt with this kind of
>> thing before?
>>
>> View Online
>>
>>
>>
>> Madison Area Perl Mongers - MadMongers
>> http://www.madmongers.org
>>
>>
>> View Online
>>
>>
>>
>> Madison Area Perl Mongers - MadMongers
>> http://www.madmongers.org