01 / 03
Bus Times
Horários ao vivo de ônibus, Luas e trem na Irlanda
2026 · Expo · React Native · TypeScript · Cloudflare Workers · R2 · SwiftUI · WidgetKit · GitHub Actions
Mais ou menos uma semana depois de chegar à Irlanda, percebi uma coisa que me incomodava: já existia um app de transporte público, mas eu continuava no ponto sem saber se o ônibus ia mesmo passar. Então fiz o meu. Ele lista as partidas dos pontos perto de você, separa o horário ao vivo do programado e põe os veículos no mapa, com os dados oficiais da TFI.

Partidas

Widgets

Mapa

§01
Transformar um feed de 250 MB em algo que cabe no celular
O feed GTFS nacional é um arquivo de 250 MB, grande demais para mandar a um celular. Um script em Node quebra esse arquivo em cerca de 10.200 JSONs pequenos, um por ponto, guardados no Cloudflare R2. Um Worker serve esses arquivos, consulta o GTFS-Realtime por cron e cuida de cache, kill switches e limite por IP.
§02
Os erros 503 em Cork
Testando em Cork, de 26% a 33% das consultas de partidas voltavam com 503, e o app avisava que não conseguia falar com o servidor. O problema era CPU: um lote de vinte pontos fazia o Worker processar 3,8 MB de JSON num cold start, passando do limite de 10 ms. Dividi o lote em blocos de oito, cada um com seu próprio limite, e os erros foram a zero.
§03
Tempo real em só 4,3% das partidas
No começo só 4,3% das partidas mostravam horário ao vivo, mesmo com o feed oficial funcionando. O feed irlandês só informa o atraso em algumas paradas de cada viagem, então o servidor leva esse atraso adiante pelo resto da viagem. A cobertura ao vivo foi para 67,9% das partidas, sem custo extra por usuário.
§04
O widget certo com o app fechado
Quem decide quando um widget atualiza é o iOS, então ficar consultando não é opção. O horário programado nunca muda, só o atraso. O app entrega ao widget uma linha do tempo de 12 entradas cobrindo a próxima hora, cada uma contando a partir do horário absoluto, e os minutos continuam certos com o app fechado.
§05
Um app de Apple Watch em SwiftUI
O app do relógio é SwiftUI nativo e nunca chama o backend. Ele mostra as partidas que o celular já buscou, enviadas por WatchConnectivity. As complications só podem ser atualizadas umas cinquenta vezes por dia, e por isso o celular só envia alguma coisa quando o dado mudou de verdade.
§06
Tempo real quebrando sem erro nenhum
De tempos em tempos o feed nacional troca os IDs das viagens, e quando isso acontecia o tempo real parava de bater com o horário programado, sem nenhum aviso. Hoje um workflow do GitHub Actions roda duas vezes por semana, compara um hash do trips.txt e só reconstrói os dados quando ele mudou. Um cron no Worker não dava conta: processar 250 MB pede muito mais que os 128 MB de memória de um Worker.








