LWP :: UserAgent请求方法的真正超时
我试图实现一个不可靠的服务器的请求。该请求是一个很好的,但我的Perl脚本不能100%成功完成。问题在于服务器偶尔会发生死锁(我们试图弄清楚原因),并且请求永远不会成功。由于服务器认为它是活动的,因此它保持套接字连接打开,因此LWP :: UserAgent的超时值对我们来说没有好处。对请求执行绝对超时的最佳方式是什么?LWP :: UserAgent请求方法的真正超时
仅供参考,这不是DNS问题。这个僵局与大量更新同时触发我们的Postgres数据库有关。出于测试目的,我们已经在服务器响应处理程序中放了一段时间(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;
}
}
你可以尝试LWPx::ParanoidAgent,LWP :: UserAgent的的子类,这是更谨慎有关它如何与远程网络服务器进行交互。
其中,它允许您指定全局超时。它由Brad Fitzpatrick开发,作为LiveJournal项目的一部分。
这个超时仍然受DNS超时的影响 – ryansstack 2012-11-20 18:45:44
据我所知,超时属性并没有考虑到DNS超时。您可以分别进行DNS查找,然后向服务器发送请求(如果有效),并为useragent设置正确的超时值。
这是服务器的DNS问题,还是其他?
编辑:它也可能是IO :: Socket的问题。尝试更新你的IO :: Socket模块,看看是否有帮助。我很确定那里有一个错误,它阻止了LWP :: UserAgent超时工作。
亚历
你可以使自己的超时是这样的:
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";
}
当人们做'加入',`时,它总是让我感到困惑 - 没有必要忙于将输入分成几行,然后再把它们连接起来,加上它需要两倍的内存。写`do {local $ /;而不是'}。 – 2008-09-17 11:50:57
最初的答案之一以下泛化也恢复了报警信号处理以前的处理程序,并增加了报警第二个电话(0)情况下,eval时钟中的呼叫会引发非警报异常,并且我们要取消警报。另外$ @检查和处理,可以添加:
sub ua_request_with_timeout {
my $ua = $_[0];
my $request = $_[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.)`enter code here`
my $timeout_for_client_sec = $ua->timeout();
our $res_has_timedout = 0;
use POSIX ':signal_h';
my $newaction = POSIX::SigAction->new(
sub { $res_has_timedout = 1; die "web request timeout"; },# the handler code ref
POSIX::SigSet->new(SIGALRM),
# not using (perl 5.8.2 and later) 'safe' switch or sa_flags
);
my $oldaction = POSIX::SigAction->new();
if(!sigaction(SIGALRM, $newaction, $oldaction)) {
log('warn',"Error setting SIGALRM handler: $!");
return $ua->request($request);
}
my $response = undef;
eval {
alarm ($timeout_for_client_sec);
$response = $ua->request($request);
alarm(0);
};
alarm(0);# cancel alarm (if eval failed because of non alarm cause)
if(!sigaction(SIGALRM, $oldaction)) {
log('warn', "Error resetting SIGALRM handler: $!");
};
if ($res_has_timedout) {
log('warn', "Timeout($timeout_for_client_sec sec) while waiting for a response from cred central");
return HTTP::Response->new(408); #408 is the HTTP timeout
} else {
return $response;
}
}
的可能的复制[如何执行在Perl明确超时?](http://stackoverflow.com/questions/15899855/how-to-enforce-a -definite-timeout-in-perl) – sixtyfootersdude 2016-02-24 22:51:45