From DBIx::HA (fudged a bit):
sub _connect_with_timeout {
my ($dsn, $username, $auth, $attrs) = @_;
my $res;
my $dbh;
my $timeout = 0;
eval {
no strict;
my $h = set_sig_handler(
'ALRM',
sub { $timeout = 1; die 'TIMEOUT'; },
{ mask=>['ALRM'], safe=>1 }
);
alarm(30);
$dbh = DBI->connect_cached($dsn, $username, $auth,
$attrs);
alarm(0);
};
alarm(0);
if ($@ or $timeout) { # there's a problem above
if ($timeout) { # it's a timeout
warn "$prefix *** CONNECT TIMED OUT in $dsn";
eval { $dbh->disconnect };
$dbh = undef;
} else { # problem in the connection
warn "$prefix Error in DBI::connect: $...@\n" if
$@;
}
}
$dbh->{private_dbixha_dsn} = $dsn if $dbh;
return $dbh;
}On Feb 27, 2009, at 9:31 PM, Lincoln A. Baxter wrote:
Hey Steve, I started to write you a message asking for a different strace, when I noticed that you are passing attributes for set_sig_handler that Sys::SigAction has no knowledge of:my $h = set_sig_handler('ALRM',sub {die "timeout";}, { trap => ['ALRM', 'INT' ], safe=>0 });The "trap" key in the hashref: { trap => ['ALRM', 'INT' ], safe=>0 } isnot used by Sys::SigAction. This reference is passed from set_sig_handler() (line 91) to mk_sig_action() (defined on line 94) where the 'flags' and the 'mask' keys are referenced (lines 98 and 99).Sys::SigAction does not know anything about the key 'trap'. And i don't know how masking ALRM or INT can help you, and flags is used for settingsigaction flags usually in the form of SA_flag that are passed to sigaction() by perl. Could you explain or fix this code, and then try again? Lincoln Author of Sys::SigAction On Tue, 2009-02-24 at 15:37 +0000, Steve Freegard wrote:Hi, I've been trying to implement a timeout wrapper for my databasefunctions to handle a database connection that is remote and thereforecould either become very slow of the link could disappear completely. I'm using something like this: use DBI; use Sys::SigAction; my($dbh); eval { my $h = set_sig_handler('ALRM',sub {die "timeout";}, { trap => [ 'ALRM', 'INT' ], safe=>0 }); alarm(30); $dbh = DBI->connect_cached(...); alarm(0); }; alarm(0); if($@) { ... } This works fine if the connection to the database is not already established and times out after 30 seconds correctly; however if thedatabase connection was established previously (and cached) it takes >200 seconds to return instead of the expected 30 seconds. An strace shows the following: rt_sigaction(SIGALRM, NULL, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], ~[KILL STOP RTMIN RT_1], 8) = 0rt_sigaction(SIGALRM, {0xd30835, [], SA_RESTORER, 0xc29a98}, {SIG_DFL},8) = 0 rt_sigprocmask(SIG_SETMASK, ~[KILL STOP RTMIN RT_1], NULL, 8) = 0rt_sigaction(SIGALRM, {0xd3419d, [ALRM], SA_RESTORER, 0xc29a98}, NULL,8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 alarm(30) = 0 rt_sigaction(SIGPIPE, {SIG_IGN}, {SIG_DFL}, 8) = 0 send(6, "Q\0\0\0\37SELECT \'DBD::Pg ping test\'\0", 32, 0) = 32 rt_sigaction(SIGPIPE, {SIG_DFL}, {SIG_IGN}, 8) = 0 poll([{fd=6, events=POLLIN|POLLERR}], 1, -1) = -1 EINTR (Interrupted system call)--- SIGALRM (Alarm clock) @ 0 (0) --- rt_sigprocmask(SIG_UNBLOCK, [ALRM], NULL, 8) = 0 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 9 setsockopt(9, SOL_TCP, TCP_NODELAY, [1], 4) = 0 fcntl64(9, F_SETFL, O_RDONLY|O_NONBLOCK) = 0 fcntl64(9, F_SETFD, FD_CLOEXEC) = 0 connect(9, {sa_family=AF_INET, sin_port=htons(5432),sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now inprogress) poll( *** hangs here for ~280 seconds *** Does anyone have any idea as to what I'm doing wrong or how to workaround this?? Kind regards, Steve.
