2010-11-24 9 views
6

Tengo un script PHP que toma un fragmento de datos de una base de datos, lo procesa y luego mira para ver si hay más datos. Este proceso se ejecuta indefinidamente y ejecuto varios de estos a la vez en un único servidor.Práctica recomendada para encontrar el origen de la terminación del script PHP

se ve algo como:

<?php 
    while($shouldStillRun) 
    { 
     // do stuff 
    } 
    logThatWeExitedLoop(); 
?> 

El problema es, después de algún tiempo, algo que hace que el proceso de dejar de correr y no he sido capaz de depurar el organismo y determinar la causa.

Esto es lo que estoy usando para obtener información hasta el momento:

  • error_log - Registro de todos los errores, pero no hay errores se muestran en el registro de errores.
  • register_shutdown_function - Ha registrado una función de apagado personalizado. Esto se llama así que sé que el servidor no está matando el proceso, se le permite terminar. (o al menos supongo que es el caso de este ser llamado?)
  • debug_backtrace - registra un debug_backtrace() en mi función de desconexión personalizado. Esto muestra solo una llamada y es mi función de apagado personalizado.
  • Registro si llega al final de la secuencia de comandos - Fuera del ciclo, tengo una función que registra que la secuencia de comandos salió del bucle (y por lo tanto estaría llegando al final del archivo de origen normalmente). Cuando la secuencia de comandos muere aleatoriamente, no está registrando esto, por lo que lo mata, lo mata mientras está en el medio del procesamiento.

¿Qué otros métodos de depuración sugerirías para encontrar al culpable?

Nota: Debo añadir que esto no es un problema con max_execution_time, que está deshabilitado para estos scripts. El tiempo antes de ser asesinado es inconsistente. Podría correr durante 10 segundos o 12 horas antes de que muera.


actualización/Solución: Gracias a todos por sus sugerencias. Al registrar el resultado, descubrí que cuando fallaba una consulta MySql, el script se configuraba en die(). D'oh. Se actualizó para registrar los errores de mysql y luego finalizar. Lo tengo funcionando ahora como un encanto!

+1

http://www.php.net/manual/en/features.connection-handling.php dice "Cuando el temporizador caduque, la secuencia de comandos se cancelará y, como en el caso anterior de desconexión del cliente, si se ha desactivado la función de apagado. registrado se llamará ". por lo que su declaración "Esto se llama así que sé que el proceso no está siendo matado por el servidor", probablemente sea falso. –

+1

Como habrás notado, debug_backtrace es inútil en una función de apagado, porque la función de apagado tiene una pila de llamadas separada de lo que sea que provocó su activación. – Piskvor

Respuesta

2

Recuerde, PHP tiene una variable en el archivo ini que indica cuánto tiempo debe ejecutarse un script. max-execution-time

Asegúrese de que no está pasando por alto esto, o use set_time_limit() para aumentar el tiempo de ejecución. ¿Este programa se ejecuta a través de un servidor web o vía cli?

Agregando: Mis malas experiencias con PHP. Repasando algunos guiones de fondo que escribí a principios de este año. Lo sentimos, pero PHP es un lenguaje de secuencias de comandos terrible para hacer cualquier cosa durante largos períodos de tiempo. Veo que el PHP más nuevo (al que no hemos actualizado) agrega la funcionalidad para forzar la ejecución del GC. El problema que he tenido es el uso de demasiada memoria porque el GC casi nunca corre para limpiarse. Si usas cosas que se refieren recursivamente a sí mismas, tampoco serán liberadas.

Crear una matriz de 100.000 elementos hace que la memoria, pero luego establecer la matriz en una matriz vacía o empalmarla, NO la libere inmediatamente y no la marque como no utilizada (también creando una nueva matriz de 100.000 elementos) aumenta la memoria).

Mi solución personal fue escribir una secuencia de comandos perl que funcionó para siempre, y el sistema ("php my_php.php"); cuando sea necesario, para que el intérprete se libere por completo. Actualmente estoy dando soporte a 5.1.6, esto podría solucionarse en 5.3+ o, como mínimo, ahora tienen comandos de GC que puede usar para forzar la limpieza del GC.

Simple script

 
#!/usr/bin/perl -w 

use strict; 

while(1) { 
    if(system("php /to/php/script.php") != 0) { 
    sleep(30); 
    } 
} 

a continuación en el script php

 
<?php 

// do a single processing block 

if($moreblockstodo) { 
    exit(0); 
} else { 
    // no? then lets sleep for a bit until we get more 
    exit(1); 
} 

?> 
+0

Ver mi nota anterior :) - El tiempo máximo de ejecución no es el problema. La secuencia de comandos se inicia con otra secuencia de comandos de inicio. Este script inicia cada proceso por: exec ('php/script/a/run.php>/dev/null 2> & 1 & echo $!', $ Salida); (obtengo el ID del proceso para poder seguir si está activo más adelante) –

+1

¿Ha intentado registrar el resultado del script en un archivo de registro? – Rahly

+1

exec ("php/script/a/run.php> /to/log/file.txt 2> & 1 & echo $!") – Rahly

0

Me conecto el estado de la función en un archivo en unos pocos lugares diferentes en cada bucle.

Puede obtener el contenido de la mayoría de las variables como una cadena con var_export, utilizando el formulario var_export($varname,true).

Puede simplemente registrar esto en un determinado archivo y vigilarlo. El último estado de la función antes de que finalice el registro debe proporcionar algunas pistas.

0

Parece que lo que está sucediendo no es un error estándar de php. Debería poder arrojar sus propios errores usando una declaración try ... catch que luego debería registrarse. No tengo más detalles aparte de eso porque estoy en mi teléfono lejos de una pc.

+0

'try {something();} catch (Excepción $ e) {trigger_error ('su texto de error:'. $ E, E_USER_WARNING);}'. Sin embargo, el código tiene que arrojar una excepción para try/catch. – JAL

2

Me gustaría registrar el uso de memoria de su secuencia de comandos. Tal vez adquiera demasiada memoria, alcance el límite de memoria y muera?

0

He encontrado esto antes en uno de nuestros proyectos en el trabajo. Tenemos una configuración similar: un script PHP verifica el DB si hay tareas por hacer (como enviar un correo electrónico, actualizar registros, procesar algunos datos también). El script PHP tiene un bucle while en el interior, que se fija a

while(true) { 
    //do something 
} 

Después de un tiempo, el script también será matado alguna manera. Ya he probado la mayoría de lo que se ha dicho aquí, como establecer max_execution_time, usar var_export para registrar todos los resultados, colocar try_catch, hacer que el script salga (php ...> output.txt) etc. y nunca hemos podido descubre cuál es el problema

Creo que PHP simplemente no está diseñado para tareas de fondo por sí mismo. Sé que no está respondiendo tu pregunta (cómo depurar esto), pero la forma en que trabajamos esto es que usamos un cronjob para llamar al archivo PHP cada 5 minutos. Esto es similar a la respuesta de Jeremy de usar una secuencia de comandos de perl: garantiza que el intérprete se libere una vez realizada la ejecución.

0

Si se trata de Linux, intente examinar los registros del sistema: el proceso podría ser cancelado por el asesino OOM (sin memoria) (es poco probable, también vería otros problemas si esto sucediera), o una falla de segmentación (a algunas versiones de PHP no les gustan algunas versiones de extensiones, lo que resulta en bloqueos extraños).

Cuestiones relacionadas