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 } is
not 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 setting
sigaction 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 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.




Reply via email to