• Publicidad

Detectar timeout de una función

Todo lo relacionado con el desarrollo Web con Perl: desde CGI hasta Mojolicious

Detectar timeout de una función

Notapor lr_emilio » 2013-09-19 11:48 @533

Hola, tengo un problema con Apache debido al timeout de una función.

Me explico: tengo una consulta por Ajax que ejecuta una función hecha en Perl. El problema es que dependiendo de los filtros que se utilicen (más o menos filtros) para una búsqueda en una base de datos puede llegar el caso de que se me produzca un timeout con el consiguiente error.

¿Existe alguna manera de detectar ese timeout para mostrar una alerta de... "especifique un poco más la búsqueda"?

Muchas gracias.

¡Un saludo!
lr_emilio
Perlero nuevo
Perlero nuevo
 
Mensajes: 25
Registrado: 2013-08-01 11:57 @539

Publicidad

Re: Detectar timeout de una función

Notapor explorer » 2013-09-19 18:10 @799

Esto está respondido en una de las preguntas de perlfaq8, que dirige la cuestión hacia la sección Signals del documento perlipc, pero recomienda el uso del módulo Sys::AlarmCall.

Del manual de DBI:
Los dos usos más comunes de las señales, en relación a DBI, son para cancelar las operaciones cuando el usuario pulse Ctrl-C (Interrupción), y para implementar un timeout usando "alarm()" y $SIG{ALRM}.

[...]

La forma tradicional de implementar un timeout es darle a $SIG{ALRM} una referencia a algún código que se ejecute cuando llegue una señal ALRM, y luego llamar a alarm($segundos) para que se genere una futura señal ALRM en el número indicado de segundos. Por ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.             eval {
  2.                 local $SIG{ALRM} = sub { die "TIMEOUT\n" };    # "\n" es requerido
  3.                 eval {
  4.                     alarm($segundos);
  5.  
  6.                     # ... código a ejecutar que sospechamos que puede alargarse en el tiempo...
  7.                 };
  8.  
  9.                 # el eval exterior captura la alarma que podría dispararse justo antes de este alarm(0)
  10.                 alarm(0);              # cancela la alarma (si el código se ejecutó a su tiempo)
  11.                 die "$@" if $@;        # si hubo algún error, lanzamos un die() para que sea capturado por eval exterior
  12.             };
  13.             if ( $@ eq "TIMEOUT\n" ) {
  14.                 ...;
  15.             }                          # si el mensaje de error es el que pusimos arriba, es que se pasó de tiempo
  16.             elsif ($@) {...}           # ¡Ops! Ocurrió otra cosa
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

El manual sigue con una explicación de por qué se usan dos eval anidados. Luego pone otro ejemplo más, pero recomiendo el uso del módulo Sys::SigAction.

También existe el módulo Time::Out, con una sintaxis mucho más sencilla.

De todos los módulos indicados, el que tiene el manual más completo, y una versión publicada más moderna, es Sys::SigAction.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Detectar timeout de una función

Notapor lr_emilio » 2013-09-20 07:05 @337

Hola, me surgen un par de dudas con el código...

¿Qué es $@?

Lo he intentado incrustar en mi búsqueda pero $@ siempre está vacío. El tiempo lo he puesto en 5 segundos para que me haga timeout, pero algo se me escapa.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $dbh = DBI->connect( "dbi:$Driv:$Base", $User, $Pass, { mysql_enable_utf8 => 1 } )
  2.     || die &MensajesErrores( "", "No se pudo Conectar a $base_datos", "", "" );
  3. $dbh->do("SET NAMES 'utf8'");
  4. my $sth1 = $dbh->prepare("SELECT $campos FROM $tabla where ($comparar) ORDER BY $queorden;");
  5. $timeout  = "N";
  6. $segundos = 5;
  7. eval {
  8.     local $SIG{ALRM} = sub { die "TIMEOUT\n" };    # "\n" es requerido
  9.     eval {
  10.         alarm($segundos);
  11.         $sth1->execute();
  12.  
  13.         # ... código a ejecutar que sospechamos que puede alargarse en el tiempo...
  14.     };
  15.  
  16.     # el eval exterior captura la alarma que podría dispararse justo antes de este alarm(0)
  17.     alarm(0);                          # cancela la alarma (si el código se ejecutó a su tiempo)
  18.     die "$@" if $@;                    # si hubo algún error, lanzamos un die() para que sea capturado por eval exterior
  19. };
  20. binmode( STDOUT, ':encoding(UTF-8)' ); # Perl hace una comprobación de que son datos UTF-8, de forma estricta
  21. print "content-type: text/html;charset=UTF-8  \n\n";
  22. print $@;
  23. if ( $@ eq "TIMEOUT\n" ) {             # si el mensaje de error es el que pusimos arriba, es que se pasó de tiempo
  24.     $timeout = "S";
  25.     $sth1->cancel;
  26. }
  27. else {                                 # ¡Ops! Ocurrió otra cosa
  28.     $timeout = "N";
  29.     while ( @Lv = $sth1->fetchrow_array() ) { push( @LiReEn2, @Lv ); }
  30.     $sth1->finish();
  31.     $dbh->disconnect || warn &LeHtm( "Mensajes/mensaje.htm", "", "No se pudo desconectar", "", "" );
  32.     if   ( $resultado != 0 ) { $mens1 = "No se ha podido encontrar"; }
  33.     else                     { $mens1 = ""; }
  34. }
  35. }
  36.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4



Un saludo
lr_emilio
Perlero nuevo
Perlero nuevo
 
Mensajes: 25
Registrado: 2013-08-01 11:57 @539

Re: Detectar timeout de una función

Notapor explorer » 2013-09-20 09:07 @422

$@ contiene el mensaje de error de la última operación realizada. Está explicada en la sección Error Variables de perlvar.

Quizás no te funciona porque estás ejecutando un binmode() y dos print() antes de preguntar por el contenido de la variable. Debes hacerlo inmediatamente.

Te aconsejo que pongas el binmode() una sola vez en el programa, lo más alto posible.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Web

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado