Desenvolvimento Web

Rastreamento de Servicos em Tempo Real com GPS e WebSockets: Guia de Implementacao

Rastreamento de Servicos em Tempo Real com GPS e WebSockets: Guia de Implementacao

O rastreamento em tempo real e uma das funcionalidades mais valorizadas em apps de servico: saber onde esta o entregador, quando o tecnico vai chegar ou acompanhar o progresso de um servico ao vivo. Este guia apresenta a arquitetura e implementacao de um sistema de rastreamento escalavel.

Componentes do sistema de rastreamento

Um sistema de rastreamento em tempo real tem tres camadas:

Emissor: o dispositivo movel do prestador/entregador que captura a localizacao via GPS e envia periodicamente para o servidor.

Broker/servidor: recebe as atualizacoes de localizacao, armazena (temporariamente), e propaga para os clientes interessados (clientes com pedido ativo, painel admin).

Receptor: o app do cliente e/ou painel admin que recebe as atualizacoes e atualiza a visualizacao no mapa em tempo real.

WebSockets vs Polling vs Server-Sent Events

Para atualizacoes em tempo real, ha tres opcoes principais:

Polling: cliente faz requisicao HTTP a cada N segundos pedindo a localizacao atual. Simples de implementar, mas desperdicador: gera requisicoes mesmo quando nenhum dado mudou.

Server-Sent Events (SSE): servidor mantem uma conexao HTTP aberta e empurra atualizacoes para o cliente quando disponivel. Unidirecional (servidor para cliente), simples, usa HTTP normal.

WebSockets: conexao bidirec full-duplex entre cliente e servidor. Mais complexo, mas necessario quando o cliente tambem precisa enviar dados de volta (como confirmacao de recebimento). Melhor para alto volume de usuarios.

Para rastreamento de entregadores, WebSockets e a escolha correta pois o app do entregador envia localizacao E o servidor precisa enviar atualizacoes de status do pedido para o entregador.

Backend com Socket.io: sala por pedido

O padrao de “sala” do Socket.io e elegante para rastreamento: cada pedido tem uma sala propria. O entregador e o cliente entram na sala do pedido, e todas as mensagens sao restritias a essa sala.

const io = require(“socket.io”)(server);

io.on(“connection”, (socket) => {
socket.on(“entrar_sala_pedido”, async ({ pedidoId, token }) => {
const usuario = await verificarToken(token);
if (!usuario) { socket.disconnect(); return; }

// Verifica que o usuario tem acesso a esse pedido
const temAcesso = await verificarAcessoPedido(usuario.id, pedidoId);
if (!temAcesso) { socket.emit(“erro”, “Sem permissao”); return; }

socket.join(`pedido:${pedidoId}`);
socket.data.userId = usuario.id;
socket.data.pedidoId = pedidoId;
});

socket.on(“atualizar_localizacao”, async ({ lat, lng, velocidade }) => {
const { pedidoId, userId } = socket.data;
if (!pedidoId) return;

// Verifica que quem emite e o entregador do pedido
const pedido = await db.query(“SELECT entregador_id FROM pedidos WHERE id=$1”, [pedidoId]);
if (pedido.rows[0]?.entregador_id !== userId) return;

// Armazena ultima localizacao
await redis.setex(`loc:${pedidoId}`, 600, JSON.stringify({ lat, lng, velocidade, ts: Date.now() }));

// Propaga para todos na sala exceto o proprio emitente
socket.to(`pedido:${pedidoId}`).emit(“localizacao”, { lat, lng, velocidade });
});
});

Escalabilidade: Redis Adapter para multiplas instancias

Se o backend precisar escalar para multiplas instancias (load balancer na frente), o Socket.io precisa de um adapter compartilhado para que mensagens emitidas em uma instancia cheguem aos sockets conectados em outras instancias:

const { createAdapter } = require(“@socket.io/redis-adapter”);
const { createClient } = require(“redis”);

const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();

await Promise.all([pubClient.connect(), subClient.connect()]);
io.adapter(createAdapter(pubClient, subClient));

Com isso, o sistema escala horizontalmente sem nenhum estado compartilhado em memoria.

ETA (Estimated Time of Arrival) dinamico

Exibir o tempo estimado de chegada e um diferencial importante. A forma mais precisa e usar a Directions API do Google com a posicao atual do entregador:

const calcularETA = async (posEntregador, posDestino) => {
const url = `https://maps.googleapis.com/maps/api/directions/json?origin=${posEntregador.lat},${posEntregador.lng}&destination=${posDestino.lat},${posDestino.lng}&departure_time=now&traffic_model=best_guess&key=${GOOGLE_MAPS_KEY}`;

const res = await fetch(url);
const data = await res.json();

if (data.status !== “OK”) return null;

const duration = data.routes[0].legs[0].duration_in_traffic?.value
|| data.routes[0].legs[0].duration.value; // segundos

return Math.ceil(duration / 60); // minutos
};

Recalcule o ETA a cada 30-60 segundos e envie para o cliente via WebSocket para que o contador no app do cliente seja atualizado dinamicamente.

Tem um projeto em mente?

Somos especialistas em transformar ideias em produtos digitais. Apps, sites, automações e IA — vamos construir juntos.

Resposta rápida Orçamento sem compromisso +100 projetos entregues
Compartilhar: