¿Procesos en segundo plano con PHP?

  • Autor Autor locoporti
  • Fecha de inicio Fecha de inicio
L

locoporti

Épsilon
Programador
Verificación en dos pasos activada
Verificado por Whatsapp
¡Hola Betas!
Aprovecharé la sección para hacerles una consulta, quizá pueden ayudarme y ahorrarme un poquito de tiempo.

Actualmente, tengo un proyecto en el cual necesito enviar correos. Estos correos, se envían al momento de hacer un click que, mediante ajax, ejecuta el código que los envía (pueden ser hasta 1000, según sea la empresa).

Lo que sucede actualmente es que me muestra un cargador mientras estos correos se envían y debido a que es una gran cantidad de correos, tarda mucho en dar una respuesta de finalizado.

Quisiera saber, si hay posibilidad de que se ejecuten en segundo plano, es decir, que funcione algo como esto:
  • - Presionan click.
  • - Darle un mensaje al usuario: "Se enviarán los correos".


Y que se vayan enviando los correos.

1. He revisado que podría hacer con cron jobs, pero como les digo, el click es una llamada a la acción (call to action).
2. Los correos son personalizados (es decir, se envía el nombre del colaborador).
3. He probado con la librería Gearman, pero no me da el suficiente soporte.
4. Uso Swiftmailer con SendGrid.

Si tienen alguna idea de cómo podría hacer esto, estaría muy agradecido.

¡Un abrazo betas!
 
Le daré una revisada, muchas gracias!
 
Con ignore_user_abort y la librería anterior vas a tener problemas similares, El navegador se quedará esperando o si se corta el proceso se parará.

Estos problemas se solucionan con una cola de tareas. La idea es que se añade una tarea a una DB Ej: "Enviar esta campaña de correos" y luego otro script (worker) independiente al navegador está a la espera de esas tareas para ejecutarlas, normalmente este worker se arranca desde SSH o linea de comandos.

Por ejemplo Github usa Resque y hay una versión para php https://github.com/chrisboulton/php-resque funciona usando Redis y en tu servidor lo que haces es ejecutar un php como "daemon", ( es un while infinito ) esperando a que existan tareas en la db que añadiste desde el php que se ejecuta en el navegador.

Esto también se usa cuando necesitas escalar con más servidores ya que estos workers pueden estar en otros servidores.

Aquí tienes un tutorial completo Background jobs with php and resque: part 1, introduction | kamisama.me

Quizás si no tienes mucha experiencia pueda resultarte un poco complejo al principio, pero es la única forma correcta al final todo lo demás te acabará dando problemas, es pasado por ello…

Suerte
 
Yo tuve un problema similar y lo que hacia era ejecutar desde php un .sh con nohup para que lo ejecutara el servidor, pero me gusta mucho la opción que propones [MENTION=110151]luishdez[/MENTION] de la cola de tareas.

Me la apunto por si tengo que usarla en algún momento :encouragement:
 
En mi opinion desde el PHP del frontend deberias "dejar en cola" esos mensajes para que luego otro PHP croneado a nivel de sistema operativo tome esos mensajes y finalmente los envie. De esa forma por un lado liberas de inmediato el Frontend y por el otro el PHP croneado y en segundo plano se ocupa del trabajo pesado y el user ni se entera.
Se entendio?
 
Yo nunca tuve problemas con ignore_user_abort que otros no sepan usarlo escapa de mis manos :topsy_turvy:
 
ignore_user_abort solo permitirá que el script continue una vez que el usuario cierre el navegador. No es la solución para eso que preguntas. Te podrás encontrara con múltiples problemas:

* El proceso si tarda el navegador no mostrará información de que la tarea se ha "recibido", por que tu tarea estará en proceso. Asi que no puedes mostrar un mensaje de "Tarea Recibida… estamos enviando tus correos"

* Una regla primordial en cualquier servicio web mínimamente profesional, es que todo proceso pesado debe salir del servidor web y del control de los usuarios ( nginx, apache etc. ) Cualquier proceso de carga te arriesgas a saturar o bloquear tu servidor… y otras peticiones secundarias. No es ideal tener una petición ocupando apache por x minutos lo normal es que tarde un segundo y se cierre, estás consumiendo recursos y arriesgando a que cualquiera pueda tumbar tu servidor…

* Como casi todo proyecto usarás sesiones en PHP, te podrás encontrar que cuando hay un proceso en este caso enviando correos, PHP hace un bloqueo del archivo de sesiones y si el usuario intenta cargar otra pagina esta se no cargará hasta que termine el otro proceso por que no puede abrir el archivo de "session" por que está bloqueado. El usuario no podrá navegar por tu web hasta que ese proceso abierto deje libre el archivo de sesiones, En este caso el usuario puede estar minutos viendo que toda tu web carga en blanco por que hay un proceso que sigue trabajando por ignore_user_abort, así que hay que tener un control de las sessiones o usar sessiones not locked, a veces esto no es posible por que se necesita acceder a datos de sessión una vez terminado el proceso y similares

Esos son algunos de los problemas

ignore_user_abort es muy útil pero solo debe usarse para tareas pequeñas como llamadas de eventos o para el logger… Como hace Symfony por ejemplo…
 
Última edición:
Muchas gracias Luis!
Pondré en practica lo que me recomendaste, un abrazo.
 
Me surge una duda con este tema.. si ejecutamos tareas en segundo plano.. hay alguna forma de saber si se ha completado o ha dado algún tipo de error?
 
Atrás
Arriba