
Tempo em software: além do happy path
O problema
A maioria dos softwares é construída sob condições ideais: relógios sincronizados, rede rápida, jobs que rodam na hora. Em produção, essas premissas falham. Este post da série "Beyond Happy Path Engineering" trata de tempo como uma fronteira de design - não como um detalhe de implementação.
Quatro tipos de tempo
O autor propõe separar o conceito de tempo em quatro categorias distintas:
- Wall-clock time: o instante no calendário (útil para auditoria e logs).
- Monotonic time: mede duração sem sofrer correções de relógio (timeouts, latência, retries).
- Logical time: ordenação de eventos via versões, offsets ou máquinas de estado - não timestamps.
- Business time: regras de domínio como períodos de cobrança, horários de loja, fusos e daylight saving.
Clock skew e o exemplo da reserva
Um fluxo de checkout reserva um item por 15 minutos. Se o worker de expiração tem um relógio 2 minutos adiantado, ele pode liberar o estoque enquanto o usuário ainda está pagando. A solução: a expiração deve ser uma transição de estado condicional (UPDATE ... WHERE state = 'reserved' AND paymentAuthorizationID IS NULL), não uma simples comparação de timestamp.
Timestamps não provam ordem
Quando eventos vêm de máquinas diferentes, ordenar por timestamp pode contar a história ao contrário. A ordenação correta exige transações, números de versão ou offsets de stream.
Medir duração com relógio monotônico
Subtrair dois wall-clock timestamps pode resultar em duração negativa se o relógio for corrigido durante a operação. Latência, backoff e deadlines devem usar relógio monotônico.
Jobs agendados são workflows
Um cron que roda a cada minuto não garante pontualidade nem execução única. Após uma pausa, o catch-up pode gerar um burst de updates. O design deve incluir batches limitados, claims com ownership, checkpointing e métricas de lag.
Tempo do usuário tem significado de produto
"Ontem" depende de qual fuso. Uma reserva de pickup às 9h em Londres precisa armazenar data local, hora local e a zona Europe/London - não apenas um offset. Offsets descrevem um momento; zonas carregam regras (incluindo DST).
Bugs de tempo se espalham em silêncio
O autor cita um exemplo real: um leaderboard com cache de 12h onde uma mudança de peso na fórmula fez metade dos perfis usar pesos novos e metade usar os antigos - sem nenhum erro nos logs. Cada leitura individual parecia correta; a inconsistência só existia entre elas.
Recomendações práticas
- Escolha o tipo de relógio para cada pergunta.
- Use monotonic time para durações e deadlines.
- Armazene instantes em UTC; exiba datas com contexto de fuso.
- Deixe o dono do estado decidir writes concorrentes (conditional updates).
- Torne expiração idempotente e reparável.
- Trate jobs agendados como workflows com batches, claims e progresso durável.
- Trate fusos como dados de domínio, não como formatação.
- Observe as premissas de tempo: lag de jobs, decisões perto de fronteiras, writes rejeitados, clock skew.
- Tenha um caminho de reconciliação para casos ambíguos que o tempo sozinho não resolve.