¿Cómo resolver set_time_limit que no afecta a PHP-CLI?set_time_limit no está afectando a PHP-CLI
#!/usr/bin/php -q
<?php
set_time_limit(2);
sleep(5); // actually, exec() call that takes > 2 seconds
echo "it didn't work again";
¿Cómo resolver set_time_limit que no afecta a PHP-CLI?set_time_limit no está afectando a PHP-CLI
#!/usr/bin/php -q
<?php
set_time_limit(2);
sleep(5); // actually, exec() call that takes > 2 seconds
echo "it didn't work again";
La solución aquí es usar pcntl_fork()
. Me temo que es solo POSIX. Será necesario compilar PHP con --enable-pcntl
y no con --disable-posix
. El código debería ser algo como esto:
<?php
function done($signo)
{
// You can do any on-success clean-up here.
die('Success!');
}
$pid = pcntl_fork();
if (-1 == $pid) {
die('Failed! Unable to fork.');
} elseif ($pid > 0) {
pcntl_signal(SIGALRM, 'done');
sleep($timeout);
posix_kill($pid, SIGKILL);
// You can do any on-failure clean-up here.
die('Failed! Process timed out and was killed.');
} else {
// You can perform whatever time-limited operation you want here.
exec($cmd);
posix_kill(posix_getppid(), SIGALRM);
}
?>
Básicamente lo que esto hace es tenedor de un nuevo proceso que se ejecuta el bloque else { ... }
. En la conclusión (exitosa) de eso, enviamos una alarma nuevamente al proceso principal, que ejecuta el bloque elseif ($pid > 0) { ... }
. Ese bloque tiene un controlador de señal registrado para la señal de alarma (la devolución de llamada done()
) que termina con éxito. Hasta que se reciba, el proceso principal duerme. Cuando se completa el tiempo de espera sleep()
, envía un SIGKILL
al proceso hijo (presumiblemente bloqueado).
+1, una respuesta muy sensata – Brad
El límite max_execution_time
, que es lo set_time_limit
conjuntos, cuenta (al menos, en Linux) el tiempo que se gasta en el proceso de PHP, mientras se trabaja.
Citando la página del manual de los set_time_limit()
:
Nota: La función
set_time_limit()
y la configuración Directivamax_execution_time
única afectar el tiempo de ejecución del script sí.
Cualquier tiempo pasado en actividad que sucede fuera de la ejecución del script como el sistema llamadas usandosystem()
, corriente operaciones, consultas de bases de datos, etc., se no incluye al determinar el tiempo máximo que el guión ha sido consecutivo .
Esto no es cierto en Windows donde el tiempo medido es real.
Cuando, está utilizando sleep()
, su script PHP no está funcionando: está a la espera ... Así que los 5 segundos que se espera no se están tomando en cuenta el límite max_execution_time
.
gracias por la respuesta, sin embargo, todavía tengo la solución al problema, ¿hay alguna manera de que pueda hacer esto usando otro enfoque? – Devrim
Bueno, yo diría que no debería no 'sleep()', si no quiere que la secuencia de comandos permanezca activa durante más tiempo que necesariamente ;-) ;;; más en serio, 'max_execution_time' se entiende como una precaución de seguridad contra scripts que tomaría demasiados recursos, y no como cualquier tipo de mecanismo de sincronización precisa. –
hay un ejecutor ejecutándose en lugar de sleep() allí. y algunas cosas de exec() se cuelgan indefinidamente. También estoy buscando matarlo desde dentro del ejecutor (en linux shell), como exec (kill_after15secs myscript.sh), pero parece que tampoco puedo encontrarlo ... – Devrim
Muy hackish, pero como uso mucho scripts cli, admito vergonzosamente por haber abofeteado un hack similar en el pasado. 2 scripts necesarios.
Su primer script cron (el que se cuelga) registra su hora de inicio y processid en un archivo plano -> la función getmypid será su amiga para esto. Un segundo script ejecutado desde cron cada (x) minutos verifica el archivo plano, elimina lo que haya pasado el tiempo de ejecución asignado, borra el archivo plano e incluso inicia sesión en otro archivo si lo desea.
Buena suerte;)
ACTUALIZACIÓN:
recordado esta pregunta y volvió a publicar esto. Mientras rebuscaba en la cuenta github de Sebastian Bergmann, tropecé con php-invoker. En palabras del autor:
clase de utilidad para invocar callables PHP con un tiempo de espera.
Aunque la respuesta actual es muy buena para uso no portátil basado en Linux, si se necesita una solución multiplataforma esta solución debe ser Windows compatibles, para aquellas pobres almas que se ejecutan en windoze. El Sr. Bergmann es un dios de PHP, estoy totalmente de acuerdo con la calidad del guión.
necesitaría algún tipo de gestor de trabajos cron para manejar procesos de inicio/inicio/detención automáticamente, pero funcionaría muy bien – Quamis
¿Podría intentar ejecutar su php vía exec y usar el comando "timeout"? (http: //packages.ubuntu.com/lúcido/tiempo de espera)
uso: timeout [-signal] comando de hora.
Super simple, funciona como se esperaba, por ejemplo ' timeout 5m/usr/bin/php/var/www/example.com/cron.php' – Moak
Estoy pensando que la secuencia de comandos se cuelga en un bucle algo. ¿Por qué no simplemente hacer un $STARTUP_TIME=time()
el inicio del script, y luego seguir revisando el ciclo si el script necesita salir?
+1 es solo una forma normal. No entiendo por qué no se usó y no se sugirió antes. –
@ OZ: Si el script * ejecuta un proceso, lo bloqueará, esperará a que finalice el proceso hijo, antes de pasar a la siguiente instrucción del script. Si el proceso ejecutado devuelve el control al script inmediatamente (por ej. usando el operador '&' de bash), esta lógica funcionará. –
me di cuenta de este comentario en el manual de PHP:
Tenga en cuenta que, bajo Linux, tiempo de sueño se ignora, pero bajo de Windows, se cuenta como tiempo de ejecución.
Por lo que tengo entendido, sleep se implementa como una llamada al sistema y, por lo tanto, es ignorado por PHP as described in the manual.
hay un exec() que se ejecuta en lugar de sueño() allí. y algunas cosas de exec() se cuelgan indefinidamente. soy también búsqueda de matar desde dentro ejecutivo (el shell de Linux), como exec (kill_after15secs myscript.sh), pero me parece que no puede encontrar que sea
ahora ver la real pregunta. Suponiendo que usted está trabajando en un entorno Lunix/Unix, se puede encontrar una solución en torno a estas líneas:
<?php $pid = system('sh test.sh >test-out.txt 2>&1 & echo $!'); ?>
Adivina qué, esto capturó el identificador de proceso del proceso de empezar. Puede iniciar sesión en una base de datos o archivo de texto junto con la marca de tiempo. En otro script cron que se ejecuta, por ejemplo, cada 5 minutos, recuperar todos los identificadores de proceso que se crearon hace 5 minutos y comprobar si todavía se están ejecutando:
<?php $status = system('ps ' . $pid); ?>
Si el proceso sigue en funcionamiento, se obtienen dos líneas de salida :
PID TTY STAT TIME COMMAND
2044 ? S 0:29 sh test.sh
Si es así, terminar de esta manera:
<?php system('kill ' . $pid); ?>
escribí un artículo sobre creating background processes in PHP (y cazarlos después). Todos los ejemplos fueron copiados de allí.
Todos los puntos conectados entre sí:
<?php
$pid = system('sh test.sh >test-out.txt 2>&1 & echo $!');
$timer = 300;
while(--$timer) {
sleep(1);
$status = system('ps ' . $pid);
$status = explode("\n", $status, 2); // I am not sure, please experiment a bit here
if (count($status) == 1 || trim($status[ 1 ]) == '') {
die('spawned process ended successfully');
}
}
system('kill ' . $pid);
die('spawned process was terminated');
?>
Como Pascal MARTIN señala, set_time_limit no es el enfoque correcto. Necesito de alguna manera matar esta secuencia de comandos después de establecer los segundos. – Devrim
mismo problema, una recompensa añadida, necesita una forma de detener el proceso cli del proceso generado por cron después de 5 minutos – Moak
Solo aclarar que la recompensa no va para Pascal MARTIN, ya que su respuesta no funciona para php-cli – Moak