trabajos segundo plano funciones ejecutar codigo asincronas php scripting background

ejecutar - funciones en segundo plano php



¿Cómo puedo ejecutar un script PHP en segundo plano después de enviar un formulario? (14)

¿Qué tal esto?

  1. Su script PHP que contiene el formulario guarda una bandera o algún valor en una base de datos o archivo.
  2. Un segundo script PHP sondea periódicamente este valor y, si se ha configurado, desencadena el script de correo electrónico de forma síncrona.

Esta segunda secuencia de comandos PHP debe configurarse para ejecutarse como cron.

Problema
Tengo un formulario que, cuando se envíe, ejecutará un código básico para procesar la información enviada e insertarla en una base de datos para mostrarla en un sitio web de notificación. Además, tengo una lista de personas que se han registrado para recibir estas notificaciones por correo electrónico y mensaje de texto. Esta lista es trivial como el momento (solo empuja alrededor de 150), sin embargo es suficiente para que tarde más de un minuto en recorrer toda la tabla de suscriptores y enviar más de 150 correos electrónicos. (Los correos electrónicos se envían individualmente a petición de los administradores del sistema de nuestro servidor de correo electrónico debido a las políticas de correo electrónico masivo).

Durante este tiempo, la persona que publicó la alerta se sentará en la última página del formulario durante casi un minuto sin ningún refuerzo positivo de que se publique su notificación. Esto conduce a otros problemas potenciales, todos los que tienen posibles soluciones que siento que son menos que ideales.

  1. En primer lugar, el póster podría pensar que el servidor está rezagado y hacer clic en el botón ''Enviar'' nuevamente, lo que hará que la secuencia de comandos comience nuevamente o se ejecute dos veces. Podría resolver esto usando JavaScript para deshabilitar el botón y reemplazar el texto para decir algo como ''Procesando ...'', sin embargo, esto no es ideal porque el usuario seguirá atascado en la página por la duración de la ejecución del script. (Además, si JavaScript está desactivado, este problema aún existe).

  2. En segundo lugar, el póster podría cerrar la pestaña o el navegador prematuramente después de enviar el formulario. La secuencia de comandos seguirá ejecutándose en el servidor hasta que intente volver a escribir en el navegador; sin embargo, si el usuario navega a cualquier página de nuestro dominio (mientras la secuencia de comandos aún se está ejecutando), el navegador no carga la página hasta que el script ha finalizado . (Esto solo ocurre cuando se cierra una pestaña o ventana del navegador y no toda la aplicación del navegador.) Aún así, esto es menos que ideal.

(Solución posible
Decidí que quería dividir la parte de "correo electrónico" de la secuencia de comandos en un archivo separado al que pueda llamar después de que se haya publicado la notificación. Originalmente pensé en poner esto en la página de confirmación después de que la notificación se haya publicado correctamente. Sin embargo, el usuario no sabrá que esta secuencia de comandos se está ejecutando y las anomalías no serán evidentes para ellos; Este script no puede fallar

Pero, ¿y si puedo ejecutar este script como un proceso en segundo plano? Entonces, mi pregunta es la siguiente: ¿cómo puedo ejecutar un script PHP para activarlo como un servicio en segundo plano y ejecutarlo de forma independiente de lo que el usuario ha hecho en el nivel del formulario?

EDITAR: Esto no puede ser cronificado. Debe ejecutarse en el instante en que se envía el formulario. Estas son notificaciones de alta prioridad. Además, los administradores del sistema que ejecutan nuestros servidores no permiten que los crones se ejecuten más de 5 minutos.


¿Y por qué no hacer una solicitud HTTP en el script e ignorar la respuesta?

http://php.net/manual/en/function.httprequest-send.php

Si realiza su solicitud en el script, debe llamar a su servidor web para ejecutarlo en segundo plano y puede (en su secuencia de comandos principal) mostrar un mensaje que le indique al usuario que el script se está ejecutando.


Como sé que no puede hacer esto de manera fácil (consulte fork exec, etc. (no trabaje en Windows)), puede invertir el enfoque, usar el fondo del navegador publicando el formulario en ajax, por lo que si la publicación aún trabajo no tienes tiempo de espera.
Esto puede ayudar incluso si tiene que hacer una elaboración larga.

Acerca del envío de correo siempre sugiere utilizar un administrador de colas, puede ser un servidor smtp local y rápido que acepte sus solicitudes y las envíe al MTA real o las ponga en una base de datos, en vez de utilizar un cron que coloque la cola en cola.
El cron puede estar en otra máquina llamando a la cola de impresión como url externa:

* * * * * wget -O /dev/null http://www.example.com/spooler.php


De todas las respuestas, ninguna consideró la ridículamente fácil función fastcgi_finish_request , que cuando se fastcgi_finish_request , fastcgi_finish_request todos los resultados restantes del navegador y cierra la sesión de Fastcgi y la conexión HTTP, mientras permite que el script se ejecute en segundo plano.

Un ejemplo:

<?php header(''Content-Type: application/json''); echo json_encode([''ok'' => true]); fastcgi_finish_request(); // The user is now disconnected from the script // do stuff with received data,


El trabajo cron de fondo parece una buena idea para esto.

Necesitará acceso ssh a la máquina para ejecutar la secuencia de comandos como cron.

$ php scriptname.php para ejecutarlo.


En mi caso tengo 3 params, uno de ellos es string (mensaje):

exec("C:/wamp/bin/php/php5.5.12/php.exe C:/test/N/trunk/api/v1/Process.php $idTest2 $idTest3 /"$mensaje/" >> c:/log.log &");

En mi Process.php tengo este código:

if (!isset($argv[1]) || !isset($argv[2]) || !isset($argv[3])) { die("Error."); } $idCurso = $argv[1]; $idDestino = $argv[2]; $mensaje = $argv[3];


En servidores Linux / Unix, puede ejecutar un trabajo en segundo plano utilizando proc_open :

$descriptorspec = array( array(''pipe'', ''r''), // stdin array(''file'', ''myfile.txt'', ''a''), // stdout array(''pipe'', ''w''), // stderr ); $proc = proc_open(''php email_script.php &'', $descriptorspec, $pipes);

El & ser el pedazo importante aquí. El script continuará incluso si el script original ha finalizado.


Haciendo un poco de experimentación con exec y shell_exec ¡he descubierto una solución que funcionó perfectamente! Elijo usar shell_exec para poder registrar cada proceso de notificación que sucede (o no). ( shell_exec regresa como una cadena y esto fue más fácil que usar exec , asignar el resultado a una variable y luego abrir un archivo para escribir en).

Estoy usando la siguiente línea para invocar el script de correo electrónico:

shell_exec("/path/to/php /path/to/send_notifications.php ''".$post_id."'' ''alert'' >> /path/to/alert_log/paging.log &");

Es importante observar el & al final del comando (como lo señala @netcoder). Este comando UNIX ejecuta un proceso en segundo plano.

Las variables adicionales rodeadas de comillas simples después de la ruta al script se establecen como variables $_SERVER[''argv''] las que puedo llamar dentro de mi script.

La secuencia de comandos de correo electrónico luego se envía a mi archivo de registro con >> y dará como resultado algo como esto:

[2011-01-07 11:01:26] Alert Notifications Sent for http://alerts.illinoisstate.edu/2049 (SCRIPT: 38.71 seconds) [2011-01-07 11:01:34] CRITICAL ERROR: Alert Notifications NOT sent for http://alerts.illinoisstate.edu/2049 (SCRIPT: 23.12 seconds)


La forma más sencilla de ejecutar un script PHP en segundo plano es

php script.php >/dev/null &

El script se ejecutará en segundo plano y la página también llegará a la página de acción más rápido.


PHP exec("php script.php") puede hacerlo.

Del Manual :

Si se inicia un programa con esta función, para que continúe ejecutándose en segundo plano, la salida del programa debe redirigirse a un archivo u otro flujo de salida. Si no lo hace, PHP se bloqueará hasta que finalice la ejecución del programa.

Por lo tanto, si redirige el resultado a un archivo de registro (lo que es una buena idea), su secuencia de comandos de llamada no se bloqueará y su secuencia de comandos de correo electrónico se ejecutará en bg.


Si estás en Windows, investiga proc_open o popen ...

Pero si estamos en el mismo servidor "Linux" que ejecuta cpanel, este es el enfoque correcto:

#!/usr/bin/php <?php $pid = shell_exec("nohup nice php -f ''path/to/your/script.php'' /dev/null 2>&1 & echo $!"); While(exec("ps $pid")) { //you can also have a streamer here like fprintf, // or fgets } ?>

No use el fork() ni el curl si tiene dudas de que pueda manejarlos, es como abusar de su servidor

Por último, en el archivo script.php que se llama arriba, tome nota de esto, asegúrese de escribir:

<?php ignore_user_abort(TRUE); set_time_limit(0); ob_start(); // <-- really optional but this is pure php //Code to be tested on background ob_flush(); flush(); //this two do the output process if you need some. //then to make all the logic possible str_repeat(" ",1500); //.for progress bars or loading images sleep(2); //standard limit ?>


Si puede acceder al servidor a través de ssh y puede ejecutar sus propios scripts, puede crear un servidor fifo simple utilizando php (aunque deberá recompilar php con soporte posix para fork ).

El servidor se puede escribir en cualquier cosa, probablemente puedas hacerlo fácilmente en Python.

O la solución más simple sería enviar un http://php.net/manual/en/function.httprequest-send.php y no leer los datos de retorno, pero el servidor podría destruir el script antes de que termine de procesarse.

Servidor de ejemplo:

<?php define(''FIFO_PATH'', ''/home/user/input.queue''); define(''FORK_COUNT'', 10); if(file_exists(FIFO_PATH)) { die(FIFO_PATH . '' exists, please delete it and try again.'' . "/n"); } if(!file_exists(FIFO_PATH) && !posix_mkfifo(FIFO_PATH, 0666)){ die(''Couldn/'t create the listening fifo.'' . "/n"); } $pids = array(); $fp = fopen(FIFO_PATH, ''r+''); for($i = 0; $i < FORK_COUNT; ++$i) { $pids[$i] = pcntl_fork(); if(!$pids[$i]) { echo "process(" . posix_getpid() . ", id=$i)/n"; while(true) { $line = chop(fgets($fp)); if($line == ''quit'' || $line === false) break; echo "processing (" . posix_getpid() . ", id=$i) :: $line/n"; // $data = json_decode($line); // processData($data); } exit(); } } fclose($fp); foreach($pids as $pid){ pcntl_waitpid($pid, $status); } unlink(FIFO_PATH); ?>

Cliente de ejemplo:

<?php define(''FIFO_PATH'', ''/home/user/input.queue''); if(!file_exists(FIFO_PATH)) { die(FIFO_PATH . '' doesn/'t exist, please make sure the fifo server is running.'' . "/n"); } function postToQueue($data) { $fp = fopen(FIFO_PATH, ''w+''); stream_set_blocking($fp, false); //don''t block $data = json_encode($data) . "/n"; if(fwrite($fp, $data) != strlen($data)) { echo "Couldn''t the server might be dead or there''s a bug somewhere/n"; } fclose($fp); } $i = 1000; while(--$i) { postToQueue(array(''xx''=>21, ''yy'' => array(1,2,3))); } ?>


Suponiendo que se está ejecutando en una plataforma * nix, use cron y el ejecutable php .

EDITAR:

Hay un buen número de preguntas que piden "ejecutar php sin cron" en SO ya. Aquí hay uno:

Programar scripts sin usar CRON

Dicho esto, la respuesta de exec () anterior suena muy prometedora :)


para el trabajador de segundo plano, creo que deberías probar esta técnica, será útil llamar tantas páginas como quieras, todas las páginas se ejecutarán de forma independiente, sin esperar a que cada página responda asincrónicamente.

form_action_page.php

<?php post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue"); //post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue2"); //post_async("http://localhost/projectname/otherpage.php", "Keywordname=anyValue"); //call as many as pages you like all pages will run at once //independently without waiting for each page response as asynchronous. //your form db insertion or other code goes here do what ever you want //above code will work as background job this line will direct hit before //above lines response ?> <?php /* * Executes a PHP page asynchronously so the current page does not have to wait for it to finish running. * */ function post_async($url,$params) { $post_string = $params; $parts=parse_url($url); $fp = fsockopen($parts[''host''], isset($parts[''port''])?$parts[''port'']:80, $errno, $errstr, 30); $out = "GET ".$parts[''path'']."?$post_string"." HTTP/1.1/r/n";//you can use POST instead of GET if you like $out.= "Host: ".$parts[''host'']."/r/n"; $out.= "Content-Type: application/x-www-form-urlencoded/r/n"; $out.= "Content-Length: ".strlen($post_string)."/r/n"; $out.= "Connection: Close/r/n/r/n"; fwrite($fp, $out); fclose($fp); } ?>

testpage.php

<? echo $_REQUEST["Keywordname"];//case1 Output > testValue //here do your background operations it will not halt main page ?>

PD: si desea enviar parámetros de url como bucle, siga esta respuesta: https://.com/a/41225209/6295712