Anual Pague anualmente e ganhe 2 meses grátis em qualquer plano pago. Ver planos
Entrar Comece grátis

A página de consumo indicava a mais, e não se mexeu um cêntimo

Comecemos pela parte que mais facilmente se perde ao ler o resto: não foi retirado dinheiro nenhum. Nenhuma carteira foi debitada duas vezes, nenhum cartão foi cobrado, nenhuma dotação de subscrição foi gasta em trabalho…

Comecemos pela parte que mais facilmente se perde ao ler o resto: não foi retirado dinheiro nenhum. Nenhuma carteira foi debitada duas vezes, nenhum cartão foi cobrado, nenhuma dotação de subscrição foi gasta em trabalho que nunca aconteceu.

O que estava avariado era um número num ecrã. Em algumas contas, a repartição do consumo na tua própria página de conta indicava a mais — na pior que medimos, 2,4 vezes o livro-razão que ela deve resumir. O livro-razão esteve certo o tempo todo. Também os tectos mensais, que são lidos de um sítio completamente diferente. Foi um defeito de apresentação, está corrigido, e eis a causa.

Uma chave que procurava algo que ninguém escreveu

O trabalho que surge por causa de algo que fizeste — actualizar um resumo diário de consumo, creditar uma recomendação, difundir uma notificação — não acontece dentro do teu pedido. O pedido escreve uma mensagem e um consumidor em segundo plano apanha-a um instante depois; é isso que impede um efeito secundário lento de tornar lenta uma página rápida.

O perigo dessa disposição é fazer o mesmo trabalho duas vezes, porque um broker volta a entregar de bom grado a mesma mensagem depois de um percalço. A defesa é uma caixa de entrada: antes de processar, um consumidor reclama a mensagem escrevendo uma linha que transporta a chave dessa mensagem, e um índice único torna impossível uma segunda reclamação.

A nossa reclamava sobre um par — o inquilino a que a mensagem pertencia, mais a chave da mensagem — e procurava esse par contra o identificador de inquilino transportado pelo envelope da mensagem, que vem preenchido.

As linhas de reclamação não transportavam identificador de inquilino nenhum. Todas estavam vazias, e estavam-no desde o início. A própria documentação da entidade afirmava, com estas palavras, que a framework o carimbava na inserção. Nunca o fez. Medido contra produção no dia em que o encontrámos: as 3.344 linhas da caixa de entrada vazias, ao passo que 1.174 de 1.451 linhas do lado produtor transportavam um inquilino real — que é precisamente por isso que ninguém suspeitou do lado que lê.

Portanto a procura pedia (inquilino, chave), a linha guardada era (nada, chave), e nunca poderiam corresponder.

Nada falhou, e é por isso que andou semanas

Uma procura que nunca pode corresponder soa a algo que deveria dar erro à primeira tentativa. Fez o contrário.

A reclamação decidiu que a mensagem era nova. A inserção embateu então no índice único e foi rejeitada como duplicado — correctamente, porque a linha já lá estava. Um ramo de recurso apanhou essa rejeição e leu-a com benevolência: outra entrega deve ter reclamado esta, aqui não há nada a fazer. O envelope ficou no estado «ainda por processar», e como ainda estava por processar, a entrega seguinte apanhou-o e fez o trabalho outra vez.

Cada consumidor reprocessava a sua própria pendência, mais ou menos a cada quarenta e cinco segundos, indefinidamente. Vinte e seis faziam-no. Uma linha de produção terminou 333 horas depois de ter chegado — e tinha estado a terminar uma e outra vez durante a maior parte desse tempo.

O que estragou de facto

Desses vinte e seis consumidores, quatro acumulam em vez de sobrescrever. Esses quatro são as projecções de facturação que a página de consumo lê, e foi aí que a coisa veio ao de cima.

Tinham uma protecção explícita contra exactamente isto, escrita depois de um incidente em Agosto em que um único evento foi aplicado nove vezes a um indicador. Essa protecção marca uma linha como bem-sucedida antes de a processar, para que uma reentrega encontre a marca e pare. A marca era escrita correctamente de todas as vezes. Depois a reclamação seguinte procurava-a com a mesma chave avariada e não a encontrava. A garantia esteve vazia desde o dia em que foi lançada.

O que isto não tocou merece ser enumerado com precisão, porque «projecção de facturação» soa alarmante e os factos não são:

  • O livro-razão estava correcto. Cada chamada de IA escreve exactamente um registo de facturação com o seu próprio instantâneo de preço, e nada neste caminho os escreve.
  • Nenhuma carteira se mexeu. Os saldos vêm do livro-razão, nunca de um resumo.
  • Nenhum tecto se mexeu. O guarda do orçamento lê um contador separado, e é esse a única fonte de verdade sobre o que gastaste este mês. Ninguém foi cortado cedo demais por causa de um número inflacionado, e ninguém passou sem dever passar.

A única coisa que lê o resumo afectado é o histórico de consumo na tua própria página de conta — o teu total e a repartição do que foi gasto em quê. É este todo o raio de impacto, e o que fez foi indicar a mais.

A metade para que ninguém olhava

A mesma procura avariada estava num segundo sítio: o caminho que corre quando uma mensagem falha. Aí nunca encontrava a linha que devia actualizar, e mesmo por baixo estava um ramo com o comentário «inalcançável na prática» — que devolvia «esta falha é terminal» em todas as falhas.

Assim o contador de novas tentativas nunca avançou e nenhuma mensagem envenenada chegou alguma vez à fila de mensagens mortas. Uma camada inteira de tratamento de erros estava desligada, por trás de um comentário que dizia a quem o lesse que ali não havia nada a verificar.

A correcção

Ambas as procuras passam agora pela chave da mensagem dentro do grupo de consumidores, que é o que o índice único impõe de qualquer forma. As chaves de mensagem derivam do identificador daquilo que as produziu, pelo que não podem colidir entre inquilinos por construção.

A documentação que afirmava o carimbo foi corrigida em vez de apagada. Aquela frase era a armadilha, e apagá-la não deixaria nada que diga que alguém finalmente verificou.

Nove testes fixam o comportamento. Seis deles falham contra o código antigo, o que confirmámos repondo o código antigo.

A limpeza a seguir

As linhas inflacionadas reparam-se sozinhas. Um worker reconstrói os resumos diários a partir do livro-razão a cada hora, numa janela de dois dias. Andava a correr o tempo todo e a perder: uma vez por hora contra um consumidor que volta a aplicar a cada quarenta e cinco segundos não é uma corrida justa.

Com o consumidor já sem se repetir, ganha. Os dois dias ainda dentro dessa janela foram reconstruídos a partir do livro-razão assim que a correcção entrou em produção. Dois dias anteriores já tinham caído fora dela, e o que resta neles é uma conta nossa mais uma diferença insignificante noutro sítio — por isso deixámo-los, em vez de alargar uma janela em produção para ir atrás disso. Pareceu-nos melhor do que insinuar que a varredura foi total.

O que levámos disto

Uma chave de desduplicação tem de espelhar o que o índice impõe de verdade, não o que o código acredita ter sido escrito. As duas metades desta eram alimentadas por campos diferentes, e nenhuma tinha alguma vez sido medida contra a outra. Agora ambas estão, e o teste que o prova fica vermelho contra a versão que estava errada.

Partilhar LinkedIn X E-mail
Experimente no seu próprio trabalhoCada resposta mostra quanto custou. Comece no plano gratuito. Comece grátis
Receba novidades do produto, não ruído Novos modelos, funcionalidades e destaques do changelog — um email curto quando algo é mesmo lançado.
Ao subscrever, aceita receber e-mails da ToRun com novidades do produto. Pode cancelar a subscrição a qualquer momento. Política de Privacidade