Question

J'essaie d'implémenter une requête sur un serveur peu fiable. La requête est agréable à avoir, mais pas à 100% pour que mon script perl se termine correctement. Le problème est que le serveur bloquera parfois de temps en temps (nous essayons de comprendre pourquoi) et que la requête ne réussira jamais. Comme le serveur pense qu'il est en direct, il maintient la connexion socket ouverte. Par conséquent, la valeur de délai d'expiration de LWP :: UserAgent ne nous est d'aucune utilité. Quel est le meilleur moyen d'imposer un délai d'expiration absolu à une demande?

Pour votre information, ce n’est pas un problème de DNS. Cette impasse a à voir avec un nombre massif de mises à jour qui ont touché notre base de données Postgres en même temps. À des fins de test, nous avons essentiellement mis une ligne while (1) {} dans le gestionnaire de réponse des serveurs.

Actuellement, le code ressemble à ceci:

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);

J'ai essayé d'utiliser des signaux pour déclencher un dépassement de délai, mais cela ne semble pas fonctionner.

eval {
    local $SIG{ALRM} = sub { die "alarm\n" };
    alarm(1);
    $res = $ua->request($req);
    alarm(0);
};
# This never runs
print "here\n";

La réponse finale que je vais utiliser a été proposée par une personne hors ligne, mais je vais en parler ici. Pour une raison quelconque, SigAction fonctionne alors que $ SIG (ALRM) ne fonctionne pas. Vous ne savez toujours pas pourquoi, mais cela a été testé pour fonctionner. Voici deux versions de travail:

# Takes a LWP::UserAgent, and a HTTP::Request, returns a HTTP::Request
sub ua_request_with_timeout {
    my $ua = 

J'essaie d'implémenter une requête sur un serveur peu fiable. La requête est agréable à avoir, mais pas à 100% pour que mon script perl se termine correctement. Le problème est que le serveur bloquera parfois de temps en temps (nous essayons de comprendre pourquoi) et que la requête ne réussira jamais. Comme le serveur pense qu'il est en direct, il maintient la connexion socket ouverte. Par conséquent, la valeur de délai d'expiration de LWP :: UserAgent ne nous est d'aucune utilité. Quel est le meilleur moyen d'imposer un délai d'expiration absolu à une demande?

Pour votre information, ce n’est pas un problème de DNS. Cette impasse a à voir avec un nombre massif de mises à jour qui ont touché notre base de données Postgres en même temps. À des fins de test, nous avons essentiellement mis une ligne while (1) {} dans le gestionnaire de réponse des serveurs.

Actuellement, le code ressemble à ceci:

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);

J'ai essayé d'utiliser des signaux pour déclencher un dépassement de délai, mais cela ne semble pas fonctionner.

eval {
    local $SIG{ALRM} = sub { die "alarm\n" };
    alarm(1);
    $res = $ua->request($req);
    alarm(0);
};
# This never runs
print "here\n";

La réponse finale que je vais utiliser a été proposée par une personne hors ligne, mais je vais en parler ici. Pour une raison quelconque, SigAction fonctionne alors que $ SIG (ALRM) ne fonctionne pas. Vous ne savez toujours pas pourquoi, mais cela a été testé pour fonctionner. Voici deux versions de travail:

<*>[0]; my $req =

J'essaie d'implémenter une requête sur un serveur peu fiable. La requête est agréable à avoir, mais pas à 100% pour que mon script perl se termine correctement. Le problème est que le serveur bloquera parfois de temps en temps (nous essayons de comprendre pourquoi) et que la requête ne réussira jamais. Comme le serveur pense qu'il est en direct, il maintient la connexion socket ouverte. Par conséquent, la valeur de délai d'expiration de LWP :: UserAgent ne nous est d'aucune utilité. Quel est le meilleur moyen d'imposer un délai d'expiration absolu à une demande?

Pour votre information, ce n’est pas un problème de DNS. Cette impasse a à voir avec un nombre massif de mises à jour qui ont touché notre base de données Postgres en même temps. À des fins de test, nous avons essentiellement mis une ligne while (1) {} dans le gestionnaire de réponse des serveurs.

Actuellement, le code ressemble à ceci:

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);

J'ai essayé d'utiliser des signaux pour déclencher un dépassement de délai, mais cela ne semble pas fonctionner.

eval {
    local $SIG{ALRM} = sub { die "alarm\n" };
    alarm(1);
    $res = $ua->request($req);
    alarm(0);
};
# This never runs
print "here\n";

La réponse finale que je vais utiliser a été proposée par une personne hors ligne, mais je vais en parler ici. Pour une raison quelconque, SigAction fonctionne alors que $ SIG (ALRM) ne fonctionne pas. Vous ne savez toujours pas pourquoi, mais cela a été testé pour fonctionner. Voici deux versions de travail:

<*>[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 =

J'essaie d'implémenter une requête sur un serveur peu fiable. La requête est agréable à avoir, mais pas à 100% pour que mon script perl se termine correctement. Le problème est que le serveur bloquera parfois de temps en temps (nous essayons de comprendre pourquoi) et que la requête ne réussira jamais. Comme le serveur pense qu'il est en direct, il maintient la connexion socket ouverte. Par conséquent, la valeur de délai d'expiration de LWP :: UserAgent ne nous est d'aucune utilité. Quel est le meilleur moyen d'imposer un délai d'expiration absolu à une demande?

Pour votre information, ce n’est pas un problème de DNS. Cette impasse a à voir avec un nombre massif de mises à jour qui ont touché notre base de données Postgres en même temps. À des fins de test, nous avons essentiellement mis une ligne while (1) {} dans le gestionnaire de réponse des serveurs.

Actuellement, le code ressemble à ceci:

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);

J'ai essayé d'utiliser des signaux pour déclencher un dépassement de délai, mais cela ne semble pas fonctionner.

eval {
    local $SIG{ALRM} = sub { die "alarm\n" };
    alarm(1);
    $res = $ua->request($req);
    alarm(0);
};
# This never runs
print "here\n";

La réponse finale que je vais utiliser a été proposée par une personne hors ligne, mais je vais en parler ici. Pour une raison quelconque, SigAction fonctionne alors que $ SIG (ALRM) ne fonctionne pas. Vous ne savez toujours pas pourquoi, mais cela a été testé pour fonctionner. Voici deux versions de travail:

<*>[0]; my $req =

J'essaie d'implémenter une requête sur un serveur peu fiable. La requête est agréable à avoir, mais pas à 100% pour que mon script perl se termine correctement. Le problème est que le serveur bloquera parfois de temps en temps (nous essayons de comprendre pourquoi) et que la requête ne réussira jamais. Comme le serveur pense qu'il est en direct, il maintient la connexion socket ouverte. Par conséquent, la valeur de délai d'expiration de LWP :: UserAgent ne nous est d'aucune utilité. Quel est le meilleur moyen d'imposer un délai d'expiration absolu à une demande?

Pour votre information, ce n’est pas un problème de DNS. Cette impasse a à voir avec un nombre massif de mises à jour qui ont touché notre base de données Postgres en même temps. À des fins de test, nous avons essentiellement mis une ligne while (1) {} dans le gestionnaire de réponse des serveurs.

Actuellement, le code ressemble à ceci:

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);

J'ai essayé d'utiliser des signaux pour déclencher un dépassement de délai, mais cela ne semble pas fonctionner.

eval {
    local $SIG{ALRM} = sub { die "alarm\n" };
    alarm(1);
    $res = $ua->request($req);
    alarm(0);
};
# This never runs
print "here\n";

La réponse finale que je vais utiliser a été proposée par une personne hors ligne, mais je vais en parler ici. Pour une raison quelconque, SigAction fonctionne alors que $ SIG (ALRM) ne fonctionne pas. Vous ne savez toujours pas pourquoi, mais cela a été testé pour fonctionner. Voici deux versions de travail:

<*>[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; } }
Était-ce utile?

La solution

Vous pouvez essayer LWPx :: ParanoidAgent , une sous-classe de LWP :: UserAgent qui fait preuve de plus de prudence quant à la manière dont il interagit avec les serveurs Web distants.

Entre autres choses, il vous permet de spécifier un délai d'expiration global. Il a été développé par Brad Fitzpatrick dans le cadre du projet LiveJournal.

Autres conseils

Vous pouvez créer votre propre délai d'attente comme ceci:

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";
}   

D'après ce que j'ai compris, la propriété de délai d'attente ne prend pas en compte les délais d'attente DNS. Il est possible que vous puissiez effectuer une recherche DNS séparément, puis adresser la demande au serveur, si cela fonctionne, avec la valeur de délai d'attente définie pour l'agent d'utilisateur.

S'agit-il d'un problème de DNS avec le serveur ou d'autre chose?

EDIT: Cela pourrait aussi être un problème avec IO :: Socket. Essayez de mettre à jour votre module IO :: Socket et voyez si cela vous aide. Je suis à peu près sûr qu’il y avait un bogue qui empêchait le dépassement de délai de LWP :: UserAgent.

Alex

La généralisation suivante de l’une des réponses originales restaure également le gestionnaire de signal d’alarme au gestionnaire précédent et ajoute un deuxième appel à alarm (0) au cas où l’appel dans l’horloge eval lève une exception non alarme et que nous souhaitons annuler. l'alarme. Une inspection et une manipulation supplémentaires de $ @ peuvent être ajoutées:

sub ua_request_with_timeout {
    my $ua = 

La généralisation suivante de l’une des réponses originales restaure également le gestionnaire de signal d’alarme au gestionnaire précédent et ajoute un deuxième appel à alarm (0) au cas où l’appel dans l’horloge eval lève une exception non alarme et que nous souhaitons annuler. l'alarme. Une inspection et une manipulation supplémentaires de $ @ peuvent être ajoutées:

<*>[0]; my $request =

La généralisation suivante de l’une des réponses originales restaure également le gestionnaire de signal d’alarme au gestionnaire précédent et ajoute un deuxième appel à alarm (0) au cas où l’appel dans l’horloge eval lève une exception non alarme et que nous souhaitons annuler. l'alarme. Une inspection et une manipulation supplémentaires de $ @ peuvent être ajoutées:

<*>[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; } }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top