Três bugs que cometi construindo um sistema de confiabilidade (e os três fingiram que deu tudo certo)
Passei os últimos dias construindo o HookSafe, uma camada que fica entre a plataforma de pagamento e o servidor do cliente para garantir que nenhum webhook se perca. A promessa do produto é uma só: se o seu servidor cair, eu seguro o evento e insisto até entregar. Cometi três bugs no caminho. O que me fez escrever este texto não foi a burrice de cada um, foi perceber, depois, que os três tinham a mesma forma: todos faziam uma falha parecer um sucesso. Num sistema cujo produto é confiabilidade, é difícil imaginar categoria de bug mais cruel. Bug 1: engoli o erro, e o sistema jurou que tinha entregue A função que entrega o evento no servidor do cliente ficou assim: go resposta, err := clienteHTTP.Do(requisicao) if err != nil { return "", nil // <- olhe com carinho } Eu quis escrever return "", err . Escrevi nil . O efeito: apontei o destino para uma porta onde não havia nada escutando. O Do devolveu um belo connection refused . E a minha função respondeu ao worker: "sem erro, chefe". O worker, obediente, marcou o evento como entregue , com o status da resposta vazio, e seguiu a vida. No banco: id | pedido_id | status | tentativas | resposta ----+-----------+----------+------------+---------- 6 | 9002 | entregue | 0 | Um evento que nunca saiu do lugar, registrado como entregue. Se isso estivesse em produção, um cliente teria pagado, não receberia nada, e o meu painel mostraria, orgulhoso, que a entrega foi um sucesso. Aquele if err != nil { return err } que a gente reclama de repetir em Go existe exatamente por isso. A linguagem te obriga a decidir o que fazer com a falha, toda vez. O preço da verbosidade é que ninguém engole um erro sem querer... a menos que digite nil . Bug 2: o log mentiu Corrigi o primeiro bug, rodei de novo, e o worker começou a cuspir isto, a cada cinco segundos, para sempre: worker: erro ao marcar morto 7: ERROR: column "reposta" does not exist worker: evento 7 esgotou as tentativas, marcado como MORTO Leia as duas linhas de novo. A primeira diz