Hi,
I've been trying to implement a timeout wrapper for my database
functions to handle a database connection that is remote and therefore
could 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 the
database 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) = 0
rt_sigaction(SIGALRM, {0xd30835, [], SA_RESTORER, 0xc29a98}, {SIG_DFL},
8) = 0
rt_sigprocmask(SIG_SETMASK, ~[KILL STOP RTMIN RT_1], NULL, 8) = 0
rt_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 in
progress)
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.