Pregunta

Este es mod_perl2 en Apache 2.2, ActiveState Perl 5.10 para Win32.

Me anular $SIG{__DIE__} y activar el indicador de RaiseError de DBI, que AFAICT de los documentos, debe llamar a mi anulación cuando una llamada base de datos falla. Parece que casi siempre, excepto en un caso, y no puedo entender por qué.

Mi guión tiene una variable our $page, y siendo mod_perl2, que puedo conseguir esto desde la anulación de esta manera:

use Carp::Trace;
my $full_trace = Carp::Trace::trace;
$full_trace =~ m/^(ModPerl::ROOT::ModPerl::Registry::.*::)handler .*$/m;
my $page;
if (defined $1)
{
    eval '$page = $' . $1 . 'page';
    if (defined $page)
    {
        $json = 1 if defined $$page{json_response};
        if (defined $$page{dbh})
        {
            my $errno = $$page{dbh}->state;
            if ($errno ~~ $$page{error_handling}{allowed})
            {
                # allowed to let it go--no report, expected possible user error at some level that couldn't be caught sooner (usually db level)
                my $errmsg = $$page{error_handling}{translation_map}{$errno};
                if (defined $errmsg)
                                    {
                                               ...

Esto funciona bien. Ahora, dentro de ese $page, tengo una ref matriz de valores de error permitidos '' que yo quiero hacer algo diferente con cuando regresan de la BD. Cuando el PP lanza uno de estos errores, quiero traducirlo en un mensaje fácil de usar, que $r->print en JSON, y la ejecución de parada (comportamiento A). Por alguna razón, en su lugar devuelve el control al script (comportamiento B).

Esta es la parte principal de mi script:

{
    $$page{error_handling}{allowed} = ['22007'];
    $$page{json_response}{result} = $page->one_liner("select 'aa'::timestamp");
    $$page{json_response}{test} = $$page{error_handling}{state};
}
    $page->make_json; # just JSONifies $$page{json_response} and prints it

Si comento hacia fuera de la primera línea, me sale un error normal (el manejo de algo inesperado) (comportamiento C), que es lo que espero, porque no he añadido el error que está ocurriendo a la lista de errores permitidos. Lo que es realmente extraño es, si corto que la primera línea y pegarlo en mi anulación $SIG{__DIE__}, funciona: la respuesta JSON se anula, impreso, y la ejecución se detiene antes de que se le asigna {test} (comportamiento A). Más extraño aún, que puede establecer {allowed} a cualquier conjunto de números, y así siempre que contenga '22007' en particular, me sale el comportamiento B. Si no es así, me sale el comportamiento C. Aún más extraño, que puede llenar en realidad mi reemplazar con cualquier cosa (advertencias, las llamadas a CORE::die, etc .--, siempre y cuando se compila) y me sale el comportamiento B todavía - a pesar de la anulación ya no contiene nada del código que haría posible! También no consigo ninguno de los resultados esperados de las llamadas a warn y CORE::die, solo silencio en los registros, así que no puedo ni siquiera intentar rastrear manualmente la ruta de ejecución a través de mi anulación.

He reiniciado Apache2.2 entre cada secuencia de comandos de salvamento. Incluso he movido la anulación en el mismo archivo script como el guión en sí, fuera del módulo donde normalmente es, y comentó a cabo todo el archivo de módulo en el que la anulación es normalmente, y se reinicia.

Si tomo a cabo esa primera línea, o tomar '22007' fuera de él, puedo warn y die y de otra manera depurar manualmente todo me gusta, y todo funciona como se esperaba. ¿Qué hay en '22007' que nunca nada salidas diferentes a pesar de restablecer el servidor? No hay referencias a '22007' en cualquier otro lugar en todo el proyecto, excepto el mapa de traducción, y pueden eliminarlo de ese archivo por completo y el reinicio y el resultado no es diferente. Se comporta como si se ha almacenado en caché mi neutralización desde temprano en el día y nunca olvidar. No es una cuestión de caché del navegador o bien, porque puedo añadir cadenas de consulta aleatorios y los resultados no son diferentes.

Esta es la experiencia más extraña y frustrante mod_perl2 que he tenido, y me he quedado sin ideas. ¿Alguien tiene alguna pista? Lo único que ocurre es que se trata de un problema de almacenamiento en caché, sin embargo, he reiniciado los servicios innumerables veces.

Como era el final del día, pensé que iba a tratar de reiniciar completamente el equipo servidor, y todavía no cambia nada. Incluso, antes de reiniciar el servidor, cambie la única línea en la que se le asigna a este {state}:

$$page{error_handling}{state} = 'my face'; # $errno;

Y, sin embargo, la salida después tuvo {test} como '22007', que es lo que debería ser sólo si había dejado = $errno intacta.

Incluso si lo fue, por ejemplo, el proxy inverso que pasa por hacer el almacenamiento en caché, esta situación no tiene sentido para mí, ya que la solicitud puede ser diferente. Después de un reinicio completo del servidor, ¿cómo puede seguir siendo la asignación de un valor que ya no está en el código, i.e., ¿cómo puede ser el uso de mi anulación $SIG{__DIE__} edad, después de un reinicio completo, cuando ya no existe en cualquier archivo?

Actualización: También intentado cambiar los errores permitidos a '42601' y cambiar la llamada db a 'select', lo que produce que el código de error, pero no añadir al mapa de la traducción. Todavía me da un comportamiento B, el establecimiento de {state} a '42601', así que no es específico para '22007'. Cualquier código de error que se pone en {allowed}, si realmente se produce dicho error, se está ejecutando la versión antigua de la anulación. Causar un error que no está en {allowed} y se ejecuta la versión actual. Pero ¿cómo sabe si el error actual está en {allowed}, o que incluso los medios que nada, antes de llegar a la anulación? (Debido a que la anulación es el único lugar donde {allowed} se grepped para el error actual.)

¿Fue útil?

Solución

Esta es mi solución temporal, pero me gustaría para resolver el misterio y no tener que agregar la línea adicional en todas partes tengo una llamada DB con errores permitidos.

package MyModule::ErrorLogging;
sub InsanityWorkaround # duplicates part of $SIG{__DIE__} override for allowed errors
{
    my ($page) = @_;
    my $r = $$page{r};
    my $errno = $$page{error_handling}{state};
    if ($errno ~~ $$page{error_handling}{allowed})
    {
        # allowed to let it go--no report, expected possible user error at some level that couldn't be caught sooner (usually db level)
        my $errmsg = $$page{error_handling}{translation_map}{$errno};
        if (defined $errmsg)
        {
            use JSON::XS qw(encode_json);
            $$page{json_response} =
            {
                error => $errmsg,
            };
            my $response = encode_json($$page{json_response});
            $r->content_type("application/json");
            $r->print($response);
            exit(0);
        }
        else
        {
            return 0; # get back to script where {state} can be checked and output can be customized even further
        }
    }
    return;
}

A continuación, se convierte en mi script:

{
    $$page{error_handling}{allowed} = ['22007']; # don't be bothered by invalid timestamp error
    $$page{json_response}{result} = $page->one_liner("select 'aa'::timestamp");
    MyModule::ErrorLogging::InsanityWorkaround($page);
}

Este comportamiento está dando una.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top