Notícias do setor
Disciplina de tempo e relógio em uma plataforma de iGaming regulada
Toda resposta que uma plataforma de jogos dá tem um tempo dentro dela. Uma aposta foi aceita em um instante, uma sessão começou em outro, uma rodada foi liquidada depois, uma janela de bônus fechou, um mercado foi suspenso, um jackpot acumulou, o dia de um relatório terminou, uma linha de log foi escrita. Nenhum desses tempos é decoração: cada um é uma afirmação que o operador pode precisar defender um dia — de um jogador com uma reclamação, de um auditor com uma pergunta, de uma revisão de incidente que reconstrói o que aconteceu, ou de uma conciliação que não fecha.
O tempo é também a única dependência que uma plataforma nunca deixa de usar. Ele é lido em cada requisição, e não chamado de vez em quando, não tem endpoint de saúde por padrão, e quando está errado a plataforma não para: ela continua servindo, em silêncio, com carimbos de tempo que já não significam o que os registros ao redor pressupõem. Por isso o tempo merece o mesmo tratamento de um livro-razão: uma única fonte de verdade, uma representação explícita, limites declarados e testes que reproduzam a falha.

As quatro partes de uma afirmação temporal
“14:03:07” ainda não é uma afirmação que alguém possa verificar. Uma afirmação temporal defensável tem quatro partes, e uma plataforma que deixe qualquer uma delas implícita vai acabar discordando dos próprios relatórios.
| Parte | A pergunta que responde | Onde falha quando não está escrita |
|---|---|---|
| O relógio | Qual máquina, sincronizada com o quê, dentro de qual tolerância | Dois serviços ordenam os mesmos eventos de formas diferentes |
| A representação | Instante com deslocamento, ou hora local sem fuso | Um tempo guardado não pode ser situado numa linha do tempo depois |
| A regra | Qual calendário, qual limite, inclusivo ou exclusivo | Um corte aplicado de um jeito na API e de outro no relatório |
| A evidência | O que foi registrado, por quem, por quanto tempo | Uma reclamação é resolvida com um log que não mostra o deslocamento |
O restante do artigo segue essas quatro partes na ordem, porque os erros se acumulam: uma fonte de relógio não escrita torna a representação ambígua, uma representação ambígua torna o limite indemonstrável, e um limite indemonstrável transforma uma conciliação rotineira em discussão.
Nomear um relógio em que a plataforma confie
O Protocolo de Tempo de Rede é a resposta comum, e o RFC 5905 descreve para que ele serve: o NTP “é amplamente usado para sincronizar relógios de computadores na Internet”, e a versão 4 “inclui melhorias fundamentais nos algoritmos de mitigação e disciplina que estendem a precisão potencial a dezenas de microssegundos com estações de trabalho modernas e redes locais rápidas”. Vale ler essa frase com cuidado antes de citá-la internamente: é uma afirmação sobre a precisão que o protocolo pode alcançar em condições favoráveis, não uma promessa sobre uma máquina virtual em um hipervisor ocupado, atrás de um link saturado, com um daemon que consulta o mesmo servidor há um mês.
Daí decorrem quatro regras práticas.
- Mais de uma fonte, e um reserva com nome. Um único servidor de referência é um ponto único de falha para algo de que cada requisição depende. Uma configuração de plataforma deve se parecer com um pequeno conjunto de fontes, e essa configuração deve ser revisável no repositório em vez de ter sido digitada uma vez num host em execução.
- Autenticar a fonte quando a exposição justifica. O RFC 8915 especifica o Network Time Security, que usa “Transport Layer Security (TLS) e criptografia autenticada com dados associados (AEAD) para fornecer segurança criptográfica ao modo cliente-servidor do Protocolo de Tempo de Rede (NTP)”. O chrony o expõe como a opção
ntsde uma diretivaserver, e sua documentação avisa que, quando a autenticação está habilitada, é importante desabilitar fontes não autenticadas que de outro modo poderiam ser usadas para influenciar o relógio. - Dar o salto na inicialização e ajustar por varredura depois. A diretiva
makestepdo chrony “força o chronyd a dar um salto no relógio do sistema se o ajuste for maior que um valor de limiar, mas apenas se não houve mais atualizações de relógio desde que o chronyd iniciou do que o limite especificado”. A orientação do próprio projeto é que “na maioria dos sistemas é desejável dar o salto do relógio do sistema apenas na inicialização, antes de iniciar programas que dependem de o tempo avançar de forma monotônica para frente”. Uma plataforma que dá saltos no relógio em operação normal decidiu que um segundo pode se repetir ou ser omitido enquanto está rodando. - Monitorar a fonte de tempo como uma dependência. Desvio e deriva por host, com alerta num limiar mais estreito do que o limite mais fino que a plataforma declara, e tratado como motivo para retirar um host das escritas sensíveis ao tempo, e não como um gráfico que alguém vai olhar depois. Um host cujo relógio está fora da tolerância não está “bem, só um pouco adiantado”: é um host que vai escrever um registro que não combina com o registro ao lado.
Guardar o instante, não a impressão
Um carimbo de tempo é um instante com uma relação declarada com o Tempo Universal Coordenado. O RFC 3339, o formato de data e hora da Internet, é explícito que seus valores expressam um deslocamento em relação ao UTC, e define uma convenção que vale conhecer: se a hora UTC é conhecida mas o deslocamento local não, o deslocamento -00:00 significa exatamente isso e “difere semanticamente de um deslocamento Z ou +00:00, que implicam que UTC é o ponto de referência preferido para a hora indicada”. O mesmo documento observa a propriedade que faz valer a pena essa disciplina: se os valores compartilham deslocamento e precisão, eles se ordenam como texto em ordem temporal.
O modo de falha é o hábito oposto: guardar o que a tela mostrava. Uma hora local sem fuso é irrecuperável depois que o deslocamento se perde. A documentação do PostgreSQL descreve a mecânica sem rodeios: se nenhum fuso é informado na entrada, assume-se que ela “está no fuso indicado pelo parâmetro TimeZone do sistema”, e em qualquer dos casos “o valor é armazenado internamente como UTC, e o fuso informado ou presumido originalmente não é retido”. O banco faz o certo com o instante e descarta o contexto humano, o que significa que uma regra que mencionava um fuso local precisa ser reconstruída a partir de outra coisa. Significa também que a configuração de um servidor pode mudar em silêncio como um carimbo de tempo sem fuso é lido.
O RFC 9557, publicado em 2024, existe justamente para essa lacuna: estende o RFC 3339 “para representar informações adicionais, incluindo um fuso horário”, precisamente porque as aplicações tratam “cada instante com um nome de fuso associado a fim de levar em conta eventos como as transições de horário de verão”. Adote-se ou não esse formato, a regra que ele codifica é a que se deve seguir: guardar o instante e manter o nome do fuso ao lado dele quando uma regra se referia a uma hora local, em vez de um deslocamento fixo calculado na hora de escrever.
Medir com um relógio que não pode ser reajustado
Dois relógios vivem na maioria dos hosts, e a documentação do Go expõe a distinção melhor que muitas especificações: “Os sistemas operacionais fornecem tanto um ‘relógio de parede’, sujeito a mudanças pela sincronização de relógio, quanto um ‘relógio monotônico’, que não está. A regra geral é que o relógio de parede serve para dizer as horas e o relógio monotônico para medir o tempo”.
Essa divisão tem uma consequência operacional. Tudo o que mede um intervalo — um tempo limite, um recuo de retentativa, uma janela de limitação de taxa, uma amostra de latência, uma contagem regressiva de sessão, um lease de bloqueio — deve ser regido por uma fonte monotônica, ou uma correção de relógio vira um defeito: um salto para frente expira trabalho que ainda tinha tempo, um salto para trás faz uma duração decorrida ficar negativa. Tudo o que registra um fato — aceitação, liquidação, acumulação — deve usar o relógio de parede, porque um instante precisa ser comparável entre máquinas.
Os dois também divergem na serialização, que é onde o erro costuma chegar à produção. A leitura monotônica “não tem significado fora do processo atual”, então os codificadores do Go a omitem, e todo construtor de análise cria um tempo sem ela. Uma duração guardada como diferença de carimbos de tempo sobrevive, portanto, a um reinício do processo como aritmética de relógio de parede, com o erro que o relógio acumulou. Se o intervalo importa através de um reinício, vale guardá-lo como um instante limite em vez de recalculá-lo a partir de uma hora de início.
Os navegadores traçam a mesma linha: a especificação High Resolution Time do W3C define uma fonte de tempo com resolução sub-milissegundo “de modo que não está sujeita a distorção ou ajustes do relógio do sistema”. Uma telemetria do lado do cliente que mede durações com um relógio de parede está medindo o relógio do dispositivo do jogador, não o da plataforma.
Há uma armadilha que nenhuma disciplina do lado da plataforma conserta, e ela merece entrar nas notas de aceitação em vez de ser descoberta em produção: em alguns sistemas o relógio monotônico para enquanto a máquina está suspensa, então uma duração medida através de uma suspensão pode reportar menos tempo do que de fato passou.
Decidir o que um segundo intercalar faz com o seu livro-razão
O Tempo Universal Coordenado não é uma contagem pura de segundos. O NIST explica o motivo: segundos intercalares são inseridos para manter o UTC “dentro de ±0,9 s da escala astronômica UT1”, a diferença atual entre UTC e o Tempo Atômico Internacional é de 37 segundos, e a sequência de eventos em um segundo intercalar positivo vai de 23h 59m 59s para 23h 59m 60s e depois para 00h 00m 00s. O apêndice do RFC 3339 registra que a decisão cabe ao IERS, que “um segundo intercalar ocorre simultaneamente em todos os fusos horários” e que a inserção é representada como YYYY-MM-DDT23:59:60Z.
Muito pouco de uma pilha típica modela isso. A documentação do Go diz que seus “cálculos de calendário sempre assumem um calendário gregoriano, sem segundos intercalares”; a maioria dos bancos de dados e bibliotecas de data adota a mesma posição, o que é razoável: um sexagésimo segundo que existe duas vezes por década não é algo que um livro-razão de apostas queira representar. A consequência é que a frota precisa escolher uma política, e há duas em uso:
- Salto. O relógio é atrasado ou retido durante o segundo extra do salto. A ordenação através desse segundo deixa de ser monotônica: dois processos diferentes podem marcar o mesmo segundo duas vezes, ou pular um. Alguns subsistemas tratam isso repetindo o último segundo do dia.
- Difusão (smear). O segundo extra é distribuído numa janela, de modo que não haja um salto único. O serviço público de NTP do Google descreve fazer isso “desde 2008, em vez de aplicar segundos intercalares aos nossos servidores com saltos de relógio”, recomenda uma “difusão linear de 24 horas do meio-dia ao meio-dia UTC” e declara o custo com honestidade: “o tempo difundido se desvia brevemente do UTC durante o período de difusão, mas se realinha após 24 horas”.
Esse custo importa para a ordenação. Durante uma janela de difusão, um relógio difundido e outro que não está diferem em até cerca de um segundo, então dois serviços com políticas diferentes podem ordenar o mesmo par de eventos de formas distintas. As regras práticas são curtas: deixar escrito qual política a frota segue, manter todos os carimbos de tempo no mesmo formato de qualquer forma, garantir que tudo o que compara horas de duas fontes compartilhe uma política ou tolere um segundo de discordância, e manter atualizada a informação de segundos intercalares do daemon de tempo: a diretiva leapsectz do chrony lê a base de fusos horários do sistema para saber quando ocorrerá o próximo segundo intercalar, e sua documentação observa que, quando um é anunciado, “o fuso precisa ser atualizado pelo menos 12 horas antes do segundo intercalar”, sem necessidade de reiniciar o daemon.
Cortes são uma regra escrita, não um arredondamento
Todo produto regulado tem cortes: o instante em que um mercado fecha, um período de bônus termina, uma sessão expira, uma janela de saque se fecha, um dia de relatório é declarado encerrado. Um corte que existe apenas como uma comparação em algum lugar do código não é uma regra; é uma coincidência que se sustenta até alguém escrever o próximo serviço.
Um corte declarado tem quatro propriedades, e elas devem estar escritas onde o time de produto, o de plataforma e quem redige o relatório possam ler.
- Qual relógio. O tempo sincronizado da própria plataforma, nunca um carimbo enviado pelo cliente. Uma regra que aceita o relógio do dispositivo é uma regra que o dispositivo pode mover.
- O limite, exatamente. Ao segundo, ao milissegundo ou ao tique da tarefa agendada — e inclusivo ou exclusivo na borda. Um intervalo semiaberto como
[abertura, fechamento)é uma decisão que a API, a interface e o relatório podem implementar de forma idêntica; “fecha à meia-noite” não é. - O que acontece com o trabalho em voo. Uma requisição que chega antes do corte e termina depois precisa de um desfecho definido. Nas apostas, o ponto de compromisso é o instante em que a plataforma a aceitou, e o guia de arquitetura de aceitação de apostas esportivas explica por que esse ponto tem de ser o autoritativo, e não o momento em que o jogador apertou um botão.
- O que se diz ao jogador. Um corte que a interface apresenta de forma diferente de como a plataforma o aplica gera contatos de suporte, não disputas sobre milissegundos.
A expiração de sessão merece uma linha própria, porque é um corte que mistura os dois relógios. Uma contagem regressiva que só precisa sobreviver dentro de um processo — um aviso de inatividade, uma janela de limitação de taxa — deve correr sobre um limite monotônico, para que uma correção de relógio não possa encerrar uma sessão antes do tempo nem estendê-la. Uma expiração que precisa sobreviver a um reinício, a um deploy ou a um balanceador movendo o jogador para outro nó tem de ser guardada como um instante com deslocamento, e sua regra deve dizer o que acontece quando o relógio é corrigido com sessões abertas.
O calendário são dados, e os dados mudam
Uma regra de negócio expressa em hora local não é estável, porque a hora local é definida por um dado que a plataforma não controla. Duas transições por ano tornam uma hora local declarada ambígua ou impossível: uma hora que ocorre duas vezes e uma hora que não ocorre de modo algum. Uma regra que diz “a promoção termina às 02:00 locais” precisa de uma resposta para a noite em que as 02:00 nunca chegam.
A base de fusos horários é atualizada com frequência conforme os governos mudam suas regras, o que tem uma consequência para tudo com data futura: o mesmo texto de regra rende um instante diferente depois de uma atualização. Por isso um corte com data futura deve ser guardado como regra — nome do fuso mais hora local — e avaliado com a versão de dados vigente, e toda execução agendada deve registrar a versão de dados que usou. Um instante calculado e congelado com um ano de antecedência é uma promessa sobre a legislação.
Os bancos de dados acrescentam mais uma dependência silenciosa. O PostgreSQL converte entre timestamp without time zone e timestamp with time zone assumindo que o valor “deve ser tomado ou dado como hora local de timezone”, e avisa que a conversão normalmente assume o TimeZone da sessão. Uma consulta que parece correta muda de significado com um ajuste de conexão. O remédio é pouco glamouroso e eficaz: nomear o fuso explicitamente na consulta e manter os instantes guardados sem ambiguidade, para que o ajuste de sessão não tenha nada a reinterpretar.
Onde termina o dia de um relatório é uma decisão
Relatórios diários e mensais têm um limite que é uma decisão de produto disfarçada de questão técnica. Um dia UTC, um dia local do regulador e um dia de negócio do operador são três intervalos diferentes com três durações diferentes numa transição de horário de verão — 23 ou 25 horas em vez de 24 —, e o limite escolhido muda quais apostas, depósitos ou bônus caem em cada período.
Escolha um, deixe escrito e publique ao lado dos números. Essa única linha resolve a maioria dos descasamentos antes de virarem chamados: o guia de conciliação de carteiras já fixa a conciliação contra o relógio do provedor e os limites do livro-razão, e um relatório cujo limite de dia está documentado pode ser comparado com o extrato de um provedor em vez de discutido com ele.
Testar as falhas de tempo que você consegue reproduzir
Defeitos de tempo são invisíveis numa suíte de testes que lê o relógio do sistema, porque o relógio do sistema é justamente o que está sob suspeita. O primeiro requisito é, portanto, estrutural: o tempo entra no código como dependência injetada e os testes a fornecem. Depois, as falhas abaixo são todas reproduzíveis, e cada uma tem um comportamento esperado definido em vez de uma esperança.
| Falha | O que ela tensiona | O que a plataforma deve fazer |
|---|---|---|
| Relógio adiantado com sessão aberta | Expiração, janelas de taxa, recuo de retentativas | O trabalho em voo não é cancelado em silêncio nem contado duas vezes |
| Relógio atrasado | Ordem de logs, durações “decorridas”, janelas de deduplicação | Sem durações negativas, sem janela repetida, ordem ainda explicável |
| Desvio entre dois serviços | Ordem de eventos reconstruída por uma tarefa | A ordem vem de um registro, não da comparação dos relógios de dois hosts |
| Fonte de tempo inalcançável | Inicialização e regime permanente | O comportamento está definido, registrado e alertado, sem deriva silenciosa |
| Dia de transição de horário de verão | Tarefas agendadas, regras em hora local | Uma regra que nomeia um fuso se resolve de forma consistente, nem duas vezes nem nunca |
| Segundo intercalar, sob qualquer política | Ordenação de toda a frota | A frota concorda com sua política e tolera a discordância que ela implica |
| Suspensão ou migração | Intervalos monotônicos | Trabalho expirado não ressuscita; um lease não fica retido duas vezes |
Dois desses testes precisam de algo além de um teste unitário. O comportamento da plataforma quando sua fonte de tempo está inalcançável pertence ao ambiente de não produção que pode ser tornado errado de propósito, e qualquer teste que meça duração numa execução longa tem de declarar com qual relógio mediu: o guia de testes de carga e resistência cobre a mesma disciplina aplicada à evidência de capacidade, onde uma medição de relógio de parede que se desvia invalida a execução que ela descreve. Quando uma revisão de incidente reconstrói uma linha do tempo, o plano de resposta a incidentes depende de uma ordem registrada corretamente antes do incidente, e o guia de evidência de auditoria é onde as expectativas sobre deslocamento e fonte pertencem.
Transformar isso em evidência de aceitação
Um comprador, um auditor ou um novo time de plataforma devem poder responder perguntas sobre tempo a partir de documentos, e não de entrevistas. O pacote é pequeno o bastante para ser montado numa tarde e específico o bastante para ser testado:
- A lista de fontes de relógio, o método de autenticação, a tolerância e como desvio e deriva são monitorados e alertados.
- O formato do instante, a regra de deslocamento e onde um nome de fuso é retido e por quê.
- O registro de cortes: cada limite, sua precisão, sua borda inclusiva ou exclusiva, o relógio que o decide e o serviço que o aplica.
- A regra de calendário para cada comportamento agendado, com a versão dos dados de fusos registrada em cada execução.
- A política de segundos intercalares e o raciocínio que aceitou seu custo.
- Os testes de falha acima, com resultados, um responsável e uma data.
- O limite do dia de relatório, publicado junto aos relatórios que ele governa.
A razão para gastar a tarde é que o tempo é a única dependência que nunca pode ficar fora do ar. Ele não pode ser desligado por flag, não tem janela de manutenção, e uma plataforma que não decidiu o que seus carimbos de tempo significam vai descobrir a decisão durante a reclamação que precisava deles. O trabalho de engenharia de uma plataforma de jogos — a disciplina de desenvolvimento de plataforma de especificar o comportamento antes de construí-lo — se aplica aqui como em qualquer outro lugar: as regras são baratas de escrever enquanto o sistema está tranquilo.
Perguntas que um comprador de plataforma faz
O sistema operacional não cuida do relógio?
Ele mantém o relógio aproximadamente correto, e isso é um trabalho mais estreito do que parece. O sistema operacional não escolhe o formato dos carimbos de tempo, não decide o que um corte significa na sua borda, não retém o fuso ao qual uma regra se referia e não registra qual política a frota seguiu durante um segundo intercalar. Essas são decisões de produto e de plataforma, e são a parte sobre a qual uma revisão vai perguntar.
Guardar os carimbos de tempo em UTC é suficiente?
Guardar em UTC é o padrão correto e é apenas metade da regra. Um instante com deslocamento é inequívoco; o contexto ao redor não é automático. Se uma regra mencionava uma hora local, o nome do fuso precisa ser retido em algum lugar para que ela possa ser avaliada depois de uma atualização dos dados de fusos, e o limite — qual relógio, qual precisão, inclusivo ou exclusivo — ainda precisa ser declarado.
Que precisão o relógio de uma plataforma realmente precisa ter?
Mais estreita do que o limite mais fino que a plataforma declara, e não mais que isso. Se o fechamento de um mercado é declarado ao segundo, a incerteza da frota tem de ficar confortavelmente dentro de um segundo; uma tolerância mais frouxa que o limite significa que esse limite é aplicado de formas diferentes em hosts diferentes, que é como dois jogadores no mesmo segundo recebem respostas diferentes. A forma correta de fixar o número é derivá-lo da regra mais estreita e então monitorar contra ele.
Segundos intercalares realmente importam para uma plataforma de cassino?
Não para a matemática do jogo, e sim para a evidência. A maioria das bibliotecas de data e bancos de dados não modela um sexagésimo segundo, o que é uma escolha de engenharia defensável. O que importa é que a escolha esteja escrita e seja consistente, para que um avanço de segundo intercalar — ou uma frota que segue uma política numa região e outra em outra — não deixe dois registros do mesmo evento discordando em um segundo sem nenhum documento que explique por quê.
