Note that there are some explanatory texts on larger screens.

plurals
  1. POTrue timeout on LWP::UserAgent request method
    text
    copied!<p>I am trying to implement a request to an unreliable server. The request is a nice to have, but not 100% required for my perl script to successfully complete. The problem is that the server will occasionally deadlock (we're trying to figure out why) and the request will never succeed. Since the server thinks it is live, it keeps the socket connection open thus LWP::UserAgent's timeout value does us no good what-so-ever. What is the best way to enforce an absolute timeout on a request? </p> <p>FYI, this is not an DNS problem. The deadlock has something to do with a massive number of updates hitting our Postgres database at the same time. For testing purposes, we've essentially put a while(1) {} line in the servers response handler. </p> <p>Currently, the code looks like so:</p> <pre><code>my $ua = LWP::UserAgent-&gt;new; ua-&gt;timeout(5); $ua-&gt;cookie_jar({}); my $req = HTTP::Request-&gt;new(POST =&gt; "http://$host:$port/auth/login"); $req-&gt;content_type('application/x-www-form-urlencoded'); $req-&gt;content("login[user]=$username&amp;login[password]=$password"); # This line never returns $res = $ua-&gt;request($req); </code></pre> <p>I've tried using signals to trigger a timeout, but that does not seem to work. </p> <pre><code>eval { local $SIG{ALRM} = sub { die "alarm\n" }; alarm(1); $res = $ua-&gt;request($req); alarm(0); }; # This never runs print "here\n"; </code></pre> <p>The final answer I'm going to use was proposed by someone offline, but I'll mention it here. For some reason, SigAction works while $SIG(ALRM) does not. Still not sure why, but this has been tested to work. Here are two working versions:</p> <pre><code># Takes a LWP::UserAgent, and a HTTP::Request, returns a HTTP::Request sub ua_request_with_timeout { my $ua = $_[0]; my $req = $_[1]; # Get whatever timeout is set for LWP and use that to # enforce a maximum timeout per request in case of server # deadlock. (This has happened.) use Sys::SigAction qw( timeout_call ); our $res = undef; if( timeout_call( 5, sub {$res = $ua-&gt;request($req);}) ) { return HTTP::Response-&gt;new( 408 ); #408 is the HTTP timeout } else { return $res; } } sub ua_request_with_timeout2 { print "ua_request_with_timeout\n"; my $ua = $_[0]; my $req = $_[1]; # Get whatever timeout is set for LWP and use that to # enforce a maximum timeout per request in case of server # deadlock. (This has happened.) my $timeout_for_client = $ua-&gt;timeout() - 2; our $socket_has_timedout = 0; use POSIX; sigaction SIGALRM, new POSIX::SigAction( sub { $socket_has_timedout = 1; die "alarm timeout"; } ) or die "Error setting SIGALRM handler: $!\n"; my $res = undef; eval { alarm ($timeout_for_client); $res = $ua-&gt;request($req); alarm(0); }; if ( $socket_has_timedout ) { return HTTP::Response-&gt;new( 408 ); #408 is the HTTP timeout } else { return $res; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload