HomeTecnologia em FocoFábrica de SoftwareFaça você mesmoComo Enviar Push Notifications em Larga Escala com PHP e Laravel

Como Enviar Push Notifications em Larga Escala com PHP e Laravel

Push notifications são um dos canais mais eficazes para engajar usuários em tempo real. No entanto, quando falamos de grandes volumes (dezenas ou até centenas de milhares de notificações), surgem desafios técnicos: latência, bloqueios de rede, falhas intermitentes e gerenciamento de filas.

Neste artigo, vamos mostrar como estruturar um pipeline robusto em Laravel + PHP para enviar notificações em massa sem sobrecarregar o servidor, usando o Apple Push Notification Service (APNs) como exemplo.

Desafios do Envio em Massa

Enviar grandes volumes não é o mesmo que disparar algumas centenas.
Problemas comuns incluem:

  • Overhead de conexões: abrir e fechar conexões TLS a cada envio gera lentidão.
  • Falhas 429 (Too Many Requests): o servidor da Apple bloqueia excesso de requisições simultâneas.
  • Tokens inválidos: dispositivos desinstalam apps e os tokens ficam “sujos”.
  • Memória: carregar todos os registros da base de uma vez pode travar o processo.

Estrutura da Base de Dados

Imagine uma tabela app_push que armazena dispositivos e plataformas:

CREATE TABLE app_push (
    id INT AUTO_INCREMENT PRIMARY KEY,
    device_token VARCHAR(255) NOT NULL,
    plataforma ENUM('iOS','Android') NOT NULL,
    filial VARCHAR(50) NOT NULL
);

E uma fila app_push_fila para armazenar os envios pendentes:

CREATE TABLE app_push_fila (
    id INT AUTO_INCREMENT PRIMARY KEY,
    device_token VARCHAR(255) NOT NULL,
    plataforma ENUM('iOS','Android') NOT NULL,
    titulo VARCHAR(255),
    mensagem TEXT,
    status ENUM('Pendente','Enviado','Erro') DEFAULT 'Pendente'
);

Código PHP/Laravel para Alta Escala

A chave para lidar com grandes volumes está em reusar a conexão HTTP/2 com o APNs, em vez de criar uma conexão por notificação.

public function enviarPushs()
{
    $http2ch = curl_init();
    $this->configurarConexao($http2ch);

    DB::table('app_push_fila')
        ->where('status', 'Pendente')
        ->orderBy('id')
        ->chunk(2000, function ($notificacoes) use ($http2ch) {
            foreach ($notificacoes as $n) {
                $payload = [
                    'aps' => [
                        'alert' => [
                            'title' => $n->titulo,
                            'body'  => $n->mensagem,
                        ],
                        'sound' => 'default',
                    ]
                ];

                $url = "https://api.push.apple.com/3/device/{$n->device_token}";
                curl_setopt($http2ch, CURLOPT_URL, $url);
                curl_setopt($http2ch, CURLOPT_POSTFIELDS, json_encode($payload));

                $result = curl_exec($http2ch);
                $status = curl_getinfo($http2ch, CURLINFO_HTTP_CODE);

                if ($status == 200) {
                    DB::table('app_push_fila')->where('id', $n->id)->update(['status' => 'Enviado']);
                } else {
                    DB::table('app_push_fila')->where('id', $n->id)->update(['status' => 'Erro']);
                }
            }
        });

    curl_close($http2ch);
}

Boas Práticas

  • Chunking: use chunk(2000) ou similar para processar em blocos e não travar a memória.
  • Retries: implemente tentativas com backoff exponencial para erros 429/5xx.
  • Remoção de tokens inválidos (410 Unregistered no APNs).
  • Collapse ID: agrupe notificações do mesmo tipo para reduzir volume entregue.
  • Monitoramento: logue sempre os retornos da Apple/Google para entender falhas.

Conclusão

Com pequenas mudanças de arquitetura — como reusar conexões e processar em blocos — você pode transformar um processo pesado e instável em uma rotina escalável e confiável, capaz de enviar 100.000+ push notifications em minutos.

Assim, seu app garante engajamento em tempo real, mesmo em cenários de alta demanda.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *