Problema
Tengo un formulario que, cuando se envía, 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 notificaciones. Además, tengo una lista de personas que se han registrado para recibir estas notificaciones por correo electrónico y mensaje SMS. Esta lista es trivial como el momento (solo empuja alrededor de 150), sin embargo, es suficiente para que se 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 según lo solicitado por 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 está publicando su notificación. Esto conduce a otros problemas potenciales, todos los que tienen posibles soluciones que creo que no son ideales.
Primero, el cartel puede pensar que el servidor está retrasado y hacer clic en el botón 'Enviar' nuevamente, lo que hace que el script comience de nuevo 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 es menos que ideal porque el usuario seguirá atascado en la página durante la ejecución del script. (Además, si JavaScript está deshabilitado, este problema aún existe).
En segundo lugar, es posible que el autor cierre la pestaña o el navegador antes de tiempo 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 dentro de nuestro dominio (mientras la secuencia de comandos aún se está ejecutando), el navegador se cuelga cargando la página hasta que finaliza la secuencia de comandos. . (Esto solo sucede cuando se cierra una pestaña o ventana del navegador y no toda la aplicación del navegador). Aún así, esto no es lo ideal.
(Posible) Solución
He decidido que quiero dividir la parte de "correo electrónico" del script en un archivo separado al que puedo 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 este script se está ejecutando y las anomalías no serán evidentes para él; Este script no puede fallar.
Pero, ¿y si puedo ejecutar este script como 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 manera completamente independiente de lo que el usuario haya hecho en el nivel del formulario?
EDITAR: Esto no se puede cron'ed. 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 crons se ejecuten con una frecuencia superior a 5 minutos.
fuente
exec()
pero nunca probé esto.ajax
e insertosleep()
con intervalo de tiempo dentro del bucle (uso foreach en mi caso) para ejecutar el proceso en segundo plano. Funciona perfectamente en mi servidor. No estoy seguro de los demás. También estoy agregandoignore_user_abort()
yset_time_limit()
(con el tiempo de finalización calculado) antes del ciclo para asegurarme de que el servidor que uso no detenga el script, incluso según mi prueba, el script completando la tarea sinignore_user_abort()
yset_time_limit()
.gearman
con php para lidiar con tareas en segundo plano. Es perfecto para escalar si se encuentra con un gran procesamiento y cargas pesadas. Deberías echarle un vistazo.Respuestas:
¡Experimentando un poco
exec
yshell_exec
he descubierto una solución que funcionó perfectamente! Elijo usarloshell_exec
para poder registrar cada proceso de notificación que ocurre (o no). (shell_exec
devuelve como una cadena y esto fue más fácil que usarexec
, asignar la salida a una variable y luego abrir un archivo para escribir).Estoy usando la siguiente línea para invocar el script de correo electrónico:
Es importante notar la
&
al final del comando (como lo señala @netcoder). Este comando de UNIX ejecuta un proceso en segundo plano.Las variables adicionales entre comillas simples después de la ruta al script se establecen como
$_SERVER['argv']
variables que puedo llamar dentro de mi script.El script de correo electrónico luego se envía a mi archivo de registro usando
>>
y generará algo como esto:fuente
$post_id
después de la ruta del script php?$post_id
; Yo prefiero echarlo directamente a un número:(int) $post_id
. (Pidiendo su atención para decidir cuál es mejor.)En servidores Linux / Unix, puede ejecutar un trabajo en segundo plano utilizando proc_open :
El
&
ser lo importante aquí. El guión continuará incluso si el guión original ha finalizado.fuente
proc_close
cuando la tarea se ha completado.proc_close
hace que el guión se cuelgue entre 15 y 25 segundos. Necesitaría mantener un registro usando la información de la tubería, así que tengo que abrir un archivo para escribir, cerrarlo y luego cerrar la conexión proc. Entonces, desafortunadamente, esta solución no me funciona.proc_close
, ¡ese es el punto! Y sí, puede canalizar a un archivo conproc_open
. Ver respuesta actualizada.De todas las respuestas, ninguna consideró la función ridículamente fácil fastcgi_finish_request , que cuando se llama, descarga toda la salida restante al navegador y cierra la sesión Fastcgi y la conexión HTTP, mientras deja que el script se ejecute en segundo plano.
Un ejemplo:
fuente
PHP
exec("php script.php")
puede hacerlo.Del manual :
Entonces, si redirige la salida a un archivo de registro (lo que es una buena idea de todos modos), su script de llamada no se bloqueará y su script de correo electrónico se ejecutará en bg.
fuente
¿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, lo ejecutará en segundo plano y puede (en su script principal) mostrar un mensaje que le indica al usuario que el script se está ejecutando.
fuente
¿Qué tal esto?
Este segundo script PHP debe configurarse para ejecutarse como cron.
fuente
Como sé que no puede hacer esto de una manera fácil (vea fork exec, etc. (no funciona en Windows)), puede ser que pueda revertir el enfoque, use 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 larga elaboración.
Sobre el envío de correo, siempre se sugiere usar un spooler, puede ser un servidor smtp local y rápido que acepte sus solicitudes y las envíe al MTA real o las coloque todo en una base de datos, en lugar de usar un cron que ponga la cola en cola.
El cron puede estar en otra máquina llamando al spooler como URL externa:
fuente
El trabajo cron en segundo plano parece una buena idea para esto.
Necesitará acceso ssh a la máquina para ejecutar el script como cron.
$ php scriptname.php
para ejecutarlo.fuente
Si puede acceder al servidor a través de ssh y puede ejecutar sus propios scripts, puede crear un servidor FIFO simple usando php (aunque tendrá que volver a compilar php con
posix
soporte parafork
).El servidor se puede escribir en cualquier cosa en realidad, probablemente puedas hacerlo fácilmente en Python.
O la solución más simple sería enviar una HttpRequest y no leer los datos devueltos, pero el servidor podría destruir el script antes de que termine de procesarse.
Servidor de ejemplo:
Cliente de ejemplo:
fuente
La forma más sencilla de ejecutar un script PHP en segundo plano es
El script se ejecutará en segundo plano y la página también llegará más rápido a la página de acción.
fuente
Suponiendo que está ejecutando en una plataforma * nix, use
cron
y elphp
ejecutable.EDITAR:
Hay bastantes preguntas que piden "ejecutar php sin cron" en SO. Aquí hay uno:
Programe scripts sin usar CRON
Dicho esto, la respuesta de exec () anterior suena muy prometedora :)
fuente
Si estás en Windows, investiga
proc_open
opopen
...Pero si estamos en el mismo servidor "Linux" que ejecuta cpanel, este es el enfoque correcto:
No los use
fork()
ocurl
si duda que pueda manejarlos, es como abusar de su servidorPor último, en el
script.php
archivo que se llama arriba, tome nota de esto, asegúrese de escribir:fuente
para el trabajador en segundo plano, creo que debería probar esta técnica, ya que ayudará a llamar a tantas páginas como desee, todas las páginas se ejecutarán a la vez de forma independiente sin esperar la respuesta de cada página como asincrónica.
form_action_page.php
testpage.php
PD: si desea enviar parámetros de URL como bucle, siga esta respuesta: https://stackoverflow.com/a/41225209/6295712
fuente
En mi caso tengo 3 params, uno de ellos es string (mensaje):
En mi Process.php tengo este código:
fuente
Esto funciona para mí. tyr esto
fuente
serialize()
function. por ejemplo, tengoindex.php
con formulario y envío valor a través de ajax a index2.php Quiero realizar el envío de datos en index2.php en segundo plano, ¿qué sugieres? graciasUtilice Amphp para ejecutar trabajos en paralelo y asincrónicamente.
Instalar la biblioteca
Muestra de código
Para su caso de uso, puede hacer algo como a continuación
fuente