Trabajo en una aplicación web algo grande, y el backend está principalmente en PHP. Hay varios lugares en el código donde necesito completar alguna tarea, pero no quiero que el usuario espere el resultado. Por ejemplo, al crear una nueva cuenta, necesito enviarles un correo electrónico de bienvenida. Pero cuando presionan el botón 'Finalizar registro', no quiero que esperen hasta que se envíe el correo electrónico, solo quiero comenzar el proceso y devolver un mensaje al usuario de inmediato.
Hasta ahora, en algunos lugares he estado usando lo que parece un hack con exec (). Básicamente haciendo cosas como:
exec("doTask.php $arg1 $arg2 $arg3 >/dev/null 2>&1 &");
Lo que parece funcionar, pero me pregunto si hay una mejor manera. Estoy considerando escribir un sistema que ponga en cola las tareas en una tabla MySQL, y un script PHP independiente de larga duración que consulta esa tabla una vez por segundo y ejecuta cualquier tarea nueva que encuentre. Esto también tendría la ventaja de permitirme dividir las tareas entre varias máquinas de trabajo en el futuro si fuera necesario.
¿Estoy reinventando la rueda? ¿Existe una solución mejor que el hack exec () o la cola MySQL?
fuente
Cuando solo desea ejecutar una o varias solicitudes HTTP sin tener que esperar la respuesta, también hay una solución PHP simple.
En el guión de llamada:
En el script script.php llamado, puede invocar estas funciones PHP en las primeras líneas:
Esto hace que el script continúe ejecutándose sin límite de tiempo cuando se cierra la conexión HTTP.
fuente
Otra forma de bifurcar procesos es mediante curl. Puede configurar sus tareas internas como un servicio web. Por ejemplo:
Luego, en sus scripts accedidos por el usuario, realice llamadas al servicio:
Su servicio puede realizar un seguimiento de la cola de tareas con mysql o lo que quiera: el asunto está envuelto en el servicio y su script solo consume URL. Esto lo libera para mover el servicio a otra máquina / servidor si es necesario (es decir, fácilmente escalable).
Agregar autorización http o un esquema de autorización personalizado (como los servicios web de Amazon) le permite abrir sus tareas para que otras personas / servicios las consuman (si lo desea) y podría llevarlo más lejos y agregar un servicio de monitoreo en la parte superior para realizar un seguimiento cola y estado de la tarea.
Se necesita un poco de trabajo de configuración, pero hay muchos beneficios.
fuente
He usado Beanstalkd para un proyecto y planeé volver a hacerlo. He encontrado que es una excelente manera de ejecutar procesos asincrónicos.
Un par de cosas que he hecho con él son:
Escribí un sistema basado en Zend-Framework para decodificar una url 'agradable', por ejemplo, para cambiar el tamaño de una imagen que llamaría
QueueTask('/image/resize/filename/example.jpg')
. La URL se decodificó primero en una matriz (módulo, controlador, acción, parámetros), y luego se convirtió a JSON para inyección en la cola misma.Luego, un script cli de larga ejecución recogió el trabajo de la cola, lo ejecutó (a través de Zend_Router_Simple) y, si es necesario, ingresó información en memcached para que el sitio web PHP lo recogiera cuando fuera necesario.
Una arruga que también puse fue que el cli-script solo se ejecutó durante 50 bucles antes de reiniciar, pero si quería reiniciar según lo planeado, lo haría de inmediato (ejecutándose a través de un script bash). Si hubo un problema y lo hice
exit(0)
(el valor predeterminado paraexit;
odie();
) primero se pausaría por un par de segundos.fuente
Si solo se trata de proporcionar tareas costosas, en caso de que se admita php-fpm, ¿por qué no utilizar la
fastcgi_finish_request()
función?Realmente no usas la asincronía de esta manera:
fastcgi_finish_request()
.Una vez más se necesita php-fpm.
fuente
Aquí hay una clase simple que codifiqué para mi aplicación web. Permite bifurcar scripts PHP y otros scripts. Funciona en UNIX y Windows.
fuente
Este es el mismo método que he estado usando durante un par de años y no he visto ni encontrado nada mejor. Como la gente ha dicho, PHP tiene un solo subproceso, por lo que no hay mucho más que pueda hacer.
De hecho, he agregado un nivel adicional a esto y eso es obtener y almacenar la identificación del proceso. Esto me permite redirigir a otra página y hacer que el usuario se siente en esa página, usando AJAX para verificar si el proceso está completo (la identificación del proceso ya no existe). Esto es útil para los casos en que la longitud de la secuencia de comandos haría que el navegador agote el tiempo de espera, pero el usuario debe esperar a que se complete esa secuencia de comandos antes del siguiente paso. (En mi caso, estaba procesando archivos ZIP grandes con archivos similares a CSV que agregan hasta 30 000 registros a la base de datos, después de lo cual el usuario debe confirmar cierta información).
También he usado un proceso similar para la generación de informes. No estoy seguro de usar el "procesamiento en segundo plano" para algo como un correo electrónico, a menos que haya un problema real con un SMTP lento. En cambio, podría usar una tabla como cola y luego tener un proceso que se ejecuta cada minuto para enviar los correos electrónicos dentro de la cola. Debería tener cuidado de enviar correos electrónicos dos veces u otros problemas similares. Consideraría un proceso de cola similar para otras tareas también.
fuente
PHP TIENE subprocesos múltiples, simplemente no está habilitado de forma predeterminada, hay una extensión llamada pthreads que hace exactamente eso. Sin embargo, necesitarás PHP compilado con ZTS. (Hilo seguro) Enlaces:
Ejemplos
Otro tutorial
pthreads PECL Extension
fuente
Es una gran idea usar cURL como lo sugiere rojoca.
Aquí hay un ejemplo. Puede monitorear text.txt mientras el script se ejecuta en segundo plano:
fuente
Lamentablemente, PHP no tiene ningún tipo de capacidades de subprocesamiento nativo. Así que creo que en este caso no tienes más remedio que usar algún tipo de código personalizado para hacer lo que quieres hacer.
Si busca en la red cosas de subprocesos de PHP, algunas personas han encontrado formas de simular subprocesos en PHP.
fuente
Si configura el encabezado HTTP Content-Length en su respuesta "Gracias por registrarse", el navegador debe cerrar la conexión después de recibir el número especificado de bytes. Esto deja el proceso del lado del servidor en ejecución (suponiendo que ignore_user_abort esté configurado) para que pueda terminar de funcionar sin hacer esperar al usuario final.
Por supuesto, deberá calcular el tamaño del contenido de su respuesta antes de representar los encabezados, pero eso es bastante fácil para respuestas cortas (escribir la salida en una cadena, llamar a strlen (), llamar a la cabecera (), procesar la cadena).
Este enfoque tiene la ventaja de no obligarlo a administrar una cola "front-end", y aunque es posible que deba trabajar un poco en el back-end para evitar que los procesos secundarios HTTP de carreras se interpongan entre sí, eso es algo que ya debe hacer , de todas formas.
fuente
header('Content-Length: 3'); echo '1234'; sleep(5);
, a pesar de que el navegador solo toma 3 caracteres, todavía espera 5 segundos antes de mostrar la respuesta. ¿Qué me estoy perdiendo?phpinfo()
. La única otra cosa que podría imaginar es que primero necesito alcanzar un tamaño mínimo de búfer, por ejemplo 256 o más bytes.Si no desea el ActiveMQ completo, le recomiendo considerar RabbitMQ . RabbitMQ es un mensaje ligero que utiliza el estándar AMQP .
Recomiendo buscar también en php-amqplib , una popular biblioteca cliente AMQP para acceder a los corredores de mensajes basados en AMQP.
fuente
Creo que deberías probar esta técnica. Ayudará a llamar tantas páginas como quieras. Todas las páginas se ejecutarán a la vez de forma independiente sin esperar que cada respuesta de la página sea asíncrona.
cornjobpage.php // página principal
testpage.php
PD: si desea enviar parámetros de URL como bucle, siga esta respuesta: https://stackoverflow.com/a/41225209/6295712
fuente
Generando nuevos procesos en el servidor usando
exec()
o directamente en otro servidor usando curl no escala muy bien en absoluto, si buscamos un ejecutivo, básicamente está llenando su servidor con procesos de larga ejecución que pueden ser manejados por otros servidores que no son web, y usar curl vincula otro servidor a menos que incorpores algún tipo de equilibrio de carga.He usado Gearman en algunas situaciones y me parece mejor para este tipo de casos de uso. Puedo usar un solo servidor de cola de trabajos para manejar básicamente la puesta en cola de todos los trabajos que el servidor debe realizar y activar los servidores de trabajo, cada uno de los cuales puede ejecutar tantas instancias del proceso de trabajo como sea necesario, y aumentar el número de servidores de trabajo según sea necesario y gírelos cuando no sea necesario También me permite cerrar los procesos de los trabajadores por completo cuando sea necesario y pone en cola los trabajos hasta que los trabajadores vuelven a estar en línea.
fuente
PHP es un lenguaje de subproceso único, por lo que no hay una forma oficial de iniciar un proceso asincrónico con él que no sea usar
exec
opopen
. Hay una publicación de blog sobre eso aquí . Su idea para una cola en MySQL también es una buena idea.Su requisito específico aquí es enviar un correo electrónico al usuario. Tengo curiosidad por saber por qué estás tratando de hacer eso de forma asíncrona, ya que enviar un correo electrónico es una tarea bastante trivial y rápida de realizar. Supongo que si está enviando toneladas de correo electrónico y su ISP lo está bloqueando por sospecha de spam, esa podría ser una razón para hacer cola, pero aparte de eso, no puedo pensar en ninguna razón para hacerlo de esta manera.
fuente