laravelbrasil / forum

Ama Laravel? Torne se um Jedi e Ajude outros Padawans
GNU General Public License v3.0
252 stars 13 forks source link

Notificação de job terminado sem socket #211

Closed marcelcunha closed 2 years ago

marcelcunha commented 3 years ago

Pessoal, na minha aplicação estou importando planilhas muito grandes, 100k linhas aproximadamente. Embora o processamento seja bem rápido, excede o tempo de requisição padrão do PHP e assim, preferi jogar esse processamento para uma fila. Tudo funcionando como deveria estar, o usuário submete a planilha e recebe uma mensagem de que será processada em segundo plano. Acontece que gostaria de notificá-lo na aplicação de que o processamento terminou.

A ideia de Broadcasting (socket) do Laravel não me atrai pois acho muito recurso gasto para notificar apenas uma vez numa funcionalidade que será usada 3 ou 4 vezes no ano.

Abordagem

Minha ideia inicial foi devolver um json com as informações de banco de dados do job disparado quando a planilha fosse submetida. No frontend já existe um mecanismo preparado para bater num endpoint, munido do json com id e outros atributos, que buscaria no DB e conseguiria dizer o processo já teria acabado e assim, lançar um popup pro usuário.

O problema dessa abordagem é que em lugar nenhum consegui pegar a instância do job, não tendo id ou outro atributo.

Se alguém souber como pego a instância do job ou tiver outra abordagem que possa usar, agradeço muito.

josemoraes commented 3 years ago

Boa noite, @marcelcunha . O caminho mais prático nesse caso é disparar um notificação. Como você comentou, esse é um processo que não é executado com frequência e que possui um tempo de execução muito grande, então certamente o usuário não vai ficar na página esperando uma notificação dizendo que o processamento aconteceu. Neste contexto, a ideia do mecanismo de notificação pode ser útil e neste caso, poderia optar por salvar no banco, e se quiser complementar, enviar por e-mail um alerta. No caso de salvar no banco, você pode ter uma página de notificações para exibi-las, ou pode somente ter um utilitário Javascript que, ou por long pooling, ou em uma execução única no load da página, faz uma consulta em um endereço de notificações da sua aplicação e exibe o pop-up (cuide da segurança da rota, use CSRF, etc). Um exemplo de como poderia usar essa estratégia:

Na Model


public function registryAndStoreFile(Request $request)
    {
        try {
            $title = File::upload($request->file('file'));
            $fileSaved = parent::create([
                'user_id' => auth()->user()->id,
                'title' => $title,
            ]);

            ValidateAndProcessFileJob::dispatch($fileSaved);

            return [
                'success'=> true,
                'message' => __('messages.files.success.store')
            ];
        } catch (\Throwable $th) {
            return [
                'success'=> false,
                'message' => $th
            ];
        }
    }

No Job

public function handle()
{
        $this->file->situation = File::PROCESSING;
        $this->file->save();
        // Seu processamento
        $userToNotify = User::find($this->file->user_id);
        if($userToNotify){
            $userToNotify->notify(new YourNotification($this->file));
        }
}

É importante ter a instância do User para executar. Esse é um código de exemplo e para a criação de um Notification, recomendo a leitura da documentação oficial, lá você terá um panorama geral dessa funcionalidade e como configurar certinho.

marcelcunha commented 3 years ago

Olá @josemoraes, acabei não mexendo mais na aplicação (o responsável teve covid), precisei acudir outros trabalhos, mas ainda não resolvi o problema. Cheguei a cogitar usar notifications mas não tinha pensado na possibilidade de salvá-las no banco de dados (a doc ajuda nessas horas). Agradeço muito pela ideia, creio que isso vai resolver meu problema.

Vou fechar a issue, se quando programar não tiver resultado, abro novamente.