Problema
Eu tenho um formulário que, quando enviado, irá executar um código básico para processar as informações enviadas e inseri-las em um banco de dados para exibição em um site de notificação. Além disso, tenho uma lista de pessoas que se inscreveram para receber essas notificações por e-mail e mensagem SMS. Esta lista é trivial como o momento (empurrando apenas cerca de 150), no entanto, é o suficiente para fazer com que demore mais de um minuto para percorrer toda a tabela de assinantes e enviar mais de 150 emails. (Os emails estão sendo enviados individualmente conforme solicitado pelos administradores do sistema de nosso servidor de email devido às políticas de email em massa.)
Durante esse tempo, o indivíduo que postou o alerta ficará sentado na última página do formulário por quase um minuto, sem qualquer reforço positivo de que sua notificação está sendo postada. Isso leva a outros problemas potenciais, todos com soluções possíveis que considero menos do que ideais.
Primeiro, o autor da postagem pode pensar que o servidor está atrasado e clicar no botão 'Enviar' novamente, fazendo com que o script reinicie ou execute duas vezes. Eu poderia resolver isso usando JavaScript para desabilitar o botão e substituir o texto para dizer algo como 'Processando ...', no entanto, isso é menos do que o ideal porque o usuário ainda ficará preso na página durante a execução do script. (Além disso, se o JavaScript estiver desativado, o problema ainda existirá.)
Em segundo lugar, o autor da postagem pode fechar a guia ou o navegador prematuramente após enviar o formulário. O script continuará em execução no servidor até tentar escrever de volta para o navegador, no entanto, se o usuário navegar para qualquer página em nosso domínio (enquanto o script ainda está em execução), o navegador para de carregar a página até que o script termine . (Isso só acontece quando uma guia ou janela do navegador é fechada e não todo o aplicativo do navegador.) Ainda assim, isso não é o ideal.
(Possível) Solução
Decidi dividir a parte "e-mail" do script em um arquivo separado que possa chamar depois que a notificação for postada. Originalmente, pensei em colocar isso na página de confirmação depois que a notificação foi postada com sucesso. No entanto, o usuário não saberá que este script está sendo executado e quaisquer anomalias não serão aparentes para ele; Este script não pode falhar.
Mas, e se eu puder executar esse script como um processo em segundo plano? Portanto, minha pergunta é a seguinte: Como posso executar um script PHP para acionar como um serviço de segundo plano e ser executado de forma completamente independente do que o usuário fez no nível do formulário?
EDIT: Isso não pode ser cron'ed. Ele deve ser executado no instante em que o formulário for enviado. Estas são notificações de alta prioridade. Além disso, os administradores de sistema que executam nossos servidores não permitem que o crons seja executado com mais frequência que 5 minutos.
fonte
exec()
mas nunca tentei isso.ajax
e insirosleep()
com intervalo de tempo dentro do loop (eu uso foreach no meu caso) para executar o processo em segundo plano. Funciona perfeitamente no meu servidor. Não tenho certeza sobre os outros. Também estou adicionandoignore_user_abort()
eset_time_limit()
(com hora de término calculada) antes do loop para ter certeza de que o script não será interrompido pelo servidor que uso, mesmo de acordo com meu teste, o script que conclui a tarefa semignore_user_abort()
eset_time_limit()
.gearman
com php para lidar com tarefas em segundo plano. É perfeito para escalar se você se deparar com um grande processamento e cargas pesadas. Você deveria dar uma olhada nisso.Respostas:
Fazendo algumas experiências com
exec
eshell_exec
eu ter descoberto uma solução que funcionou perfeitamente! Eu escolho usarshell_exec
para poder registrar todos os processos de notificação que acontecem (ou não). (shell_exec
retorna como uma string e isso era mais fácil do que usarexec
, atribuindo a saída a uma variável e, em seguida, abrindo um arquivo para gravar.)Estou usando a seguinte linha para invocar o script de e-mail:
É importante observar o
&
no final do comando (como apontado por @netcoder). Este comando UNIX executa um processo em segundo plano.As variáveis extras entre aspas simples após o caminho para o script são definidas como
$_SERVER['argv']
variáveis que posso chamar dentro do meu script.O script de e-mail então sai para o meu arquivo de log usando o
>>
e vai gerar algo assim:fonte
$post_id
depois do caminho do script php?$post_id
; Eu prefiro lançá-lo diretamente para um número:(int) $post_id
. (Chamando sua atenção para decidir o que é melhor.)Em servidores Linux / Unix, você pode executar uma tarefa em segundo plano usando proc_open :
O
&
ser a parte importante aqui. O script continuará mesmo se o script original tiver terminado.fonte
proc_close
quando a tarefa é concluída.proc_close
faz o script travar por cerca de 15 a 25 segundos. Eu precisaria manter um log usando as informações do pipe, então eu tenho que abrir um arquivo a ser escrito, fechá-lo e, em seguida, fechar a conexão proc. Então, infelizmente, essa solução não funciona para mim.proc_close
, esse é o ponto! E sim, você pode enviar para um arquivo comproc_open
. Veja a resposta atualizada.De todas as respostas, nenhuma considerou a ridiculamente fácil fastcgi_finish_request função , que quando chamada, libera toda a saída restante para o navegador e fecha a sessão Fastcgi e a conexão HTTP, enquanto permite que o script seja executado em segundo plano.
Um exemplo:
fonte
PHP
exec("php script.php")
pode fazer isso.Do Manual :
Portanto, se você redirecionar a saída para um arquivo de log (o que é uma boa idéia de qualquer maneira), seu script de chamada não travará e seu script de email será executado em bg.
fonte
E por que não fazer uma solicitação HTTP no script e ignorar a resposta?
http://php.net/manual/en/function.httprequest-send.php
Se você fizer sua solicitação no script, você precisará chamar o seu servidor web que o executará em segundo plano e você poderá (no script principal) mostrar uma mensagem informando ao usuário que o script está sendo executado.
fonte
Que tal agora?
Este segundo script PHP deve ser configurado para ser executado como um cron.
fonte
Como eu sei que você não pode fazer isso de maneira fácil (ver fork exec etc (não funciona no windows)), pode ser que você pode inverter a abordagem, use o fundo do navegador postando o formulário em ajax, portanto, se o post ainda trabalho você não tem tempo de espera.
Isso pode ajudar mesmo que você precise fazer uma longa elaboração.
Sobre o envio de email é sempre sugerido usar um spooler, pode ser um servidor smtp local & quick que aceita seus pedidos e os envia para o MTA real ou coloca tudo em um banco de dados, do que usar um cron que faz o spool da fila.
O cron pode estar em outra máquina chamando o spooler como url externo:
fonte
O cron job em segundo plano parece uma boa ideia para isso.
Você precisará de acesso ssh à máquina para executar o script como um cron.
$ php scriptname.php
para executá-lo.fonte
Se você pode acessar o servidor via ssh e pode executar seus próprios scripts, você pode fazer um servidor fifo simples usando php (embora você tenha que recompilar o php com
posix
suporte parafork
).O servidor pode ser escrito em qualquer coisa, você provavelmente pode fazer isso facilmente em python.
Ou a solução mais simples seria enviar um HttpRequest e não ler os dados de retorno, mas o servidor pode destruir o script antes de terminar o processamento.
Servidor de exemplo:
Cliente de exemplo:
fonte
A maneira mais simples de executar um script PHP em segundo plano é
O script será executado em segundo plano e a página também alcançará a página de ação mais rapidamente.
fonte
Supondo que você esteja executando em uma plataforma * nix, use
cron
e ophp
executável.EDITAR:
Já existem várias questões pedindo para "rodar php sem cron" no SO. Aqui está um:
Agende scripts sem usar CRON
Dito isso, a resposta exec () acima parece muito promissora :)
fonte
Se você estiver no Windows, pesquise
proc_open
oupopen
...Mas se estivermos no mesmo servidor "Linux" executando cpanel, então esta é a abordagem certa:
Não use
fork()
oucurl
se você duvida que pode lidar com eles, é como abusar do seu servidorPor último, no
script.php
arquivo chamado acima, tome nota disso, certifique-se de ter escrito:fonte
para o trabalhador em segundo plano, acho que você deve tentar essa técnica. Ela ajudará a chamar quantas páginas quiser, todas as páginas serão executadas de uma vez, independentemente, sem esperar por cada resposta de página como assíncrona.
form_action_page.php
testpage.php
PS: se você deseja enviar parâmetros de url como loop, siga esta resposta: https://stackoverflow.com/a/41225209/6295712
fonte
No meu caso, tenho 3 parâmetros, um deles é string (mensaje):
No meu Process.php, tenho este código:
fonte
Isso funciona para mim. tirem isso
fonte
serialize()
função. por exemplo, tenhoindex.php
com form e envio valor via ajax para index2.php quero realizar o envio de dados em index2.php em background o que você sugere? obrigadoUse Amphp para executar trabalhos em paralelo e de forma assíncrona.
Instale a biblioteca
Amostra de código
Para o seu caso de uso, você pode fazer algo como a seguir
fonte