LWP :: UserAgent请求方法上的真实超时
时间:2020-03-05 18:56:13 来源:igfitidea点击:
我正在尝试对不可靠的服务器实施请求。该请求很不错,但是我的perl脚本成功完成并不需要100%。问题是服务器偶尔会死锁(我们试图找出原因),并且请求将永远不会成功。由于服务器认为它是活动的,因此它保持套接字连接处于打开状态,因此LWP :: UserAgent的超时值对我们毫无用处。对请求强制绝对超时的最佳方法是什么?
仅供参考,这不是DNS问题。僵局与同时访问我们的Postgres数据库的大量更新有关。为了进行测试,我们实质上在服务器响应处理程序中放置了while(1){}行。
当前,代码如下所示:
my $ua = LWP::UserAgent->new; ua->timeout(5); $ua->cookie_jar({}); my $req = HTTP::Request->new(POST => "http://$host:$port/auth/login"); $req->content_type('application/x-www-form-urlencoded'); $req->content("login[user]=$username&login[password]=$password"); # This line never returns $res = $ua->request($req);
我试过使用信号触发超时,但这似乎不起作用。
eval { local $SIG{ALRM} = sub { die "alarm\n" }; alarm(1); $res = $ua->request($req); alarm(0); }; # This never runs print "here\n";
我要使用的最终答案是由离线用户提出的,但我将在这里提及。由于某些原因,SigAction可以工作,而$ SIG(ALRM)则不能。仍然不确定为什么,但这已经过测试。这是两个工作版本:
# 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->request($req);}) ) { return HTTP::Response->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->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->request($req); alarm(0); }; if ( $socket_has_timedout ) { return HTTP::Response->new( 408 ); #408 is the HTTP timeout } else { return $res; } }
解决方案
回答
据我了解,超时属性未考虑DNS超时。有可能我们可以单独进行DNS查找,然后向服务器发出请求(如果可行),并为useragent设置正确的超时值。
这是服务器的DNS问题还是其他问题?
编辑:这也可能是IO :: Socket的问题。尝试更新IO :: Socket模块,看看是否有帮助。我很确定其中存在一个阻止LWP :: UserAgent超时工作的错误。
亚历克斯
回答
我们可以尝试LWPx :: ParanoidAgent,它是LWP :: UserAgent的子类,它在与远程Web服务器交互时更加谨慎。
除其他外,它允许我们指定全局超时。它是Brad Fitzpatrick作为LiveJournal项目的一部分开发的。
回答
我们可以这样设置自己的超时时间:
use LWP::UserAgent; use IO::Pipe; my $agent = new LWP::UserAgent; my $finished = 0; my $timeout = 5; $SIG{CHLD} = sub { wait, $finished = 1 }; my $pipe = new IO::Pipe; my $pid = fork; if($pid == 0) { $pipe->writer; my $response = $agent->get("http://stackoverflow.com/"); $pipe->print($response->content); exit; } $pipe->reader; sleep($timeout); if($finished) { print "Finished!\n"; my $content = join('', $pipe->getlines); } else { kill(9, $pid); print "Timed out.\n"; }