Blogue ·
Duas regras, e uma ligação morta entre elas
Um rastreio de 1776 páginas encontrou exatamente 18 URL partidos. As duas regras que os produziram estavam certas; ninguém testara o que há entre elas.
Por Provibr
Rastreámos o site de produção como deve ser pela primeira vez em algum tempo: todas as ligações internas seguidas, todas as alternativas de língua declaradas verificadas, todos os blocos de dados estruturados validados, todas as imagens verificadas quanto ao texto alternativo.
1776 páginas, 1750 entradas de sitemap, e exatamente um defeito. Zero órfãs, zero cadeias de redirecionamento, zero erros de alternativa de língua ao longo de 17218 declarações, zero blocos de dados estruturados inválidos ao longo de 1642, zero imagens sem texto alternativo ao longo de 15463, e 920 imagens de pré-visualização social todas a responder 200.
O único defeito eram 18 URL a devolver 404: as páginas de documentação de dois painéis de faturação, nas nove línguas. Cada um desses 18 tinha exatamente uma ligação interna a apontar para ela, a partir da página de integração do mesmo produto na mesma língua.
As duas metades disso são de propósito. É isso que faz com que valha a pena registá-lo.
As duas regras
Algumas das nossas integrações estão por trás de um interruptor de lançamento. Com o interruptor desligado, o fornecedor desaparece do catálogo, do sitemap, dos contadores e do seletor de tipo no painel, tudo derivado de uma só tabela para que não haja uma segunda lista de que alguém se esqueça.
Duas delas não são bem vulgares. Para o FOSSBilling e o Paymenter há um módulo que se instala no painel deles, e a página em /integrations/fossbilling descreve esse módulo. Não é uma página sobre uma ligação que oferecemos; é uma página sobre uma coisa que se pode descarregar hoje. Por isso há uma regra que mantém essas duas páginas de integração de pé quando o fornecedor por trás do interruptor está escondido, e ela leva a sua razão na fonte.
A página de documentação é o caso oposto. /docs/fossbilling descreve a ligação, que é exatamente o que o interruptor desliga, por isso desaparece com o fornecedor.
Ambas as regras estão certas. Um slug, duas superfícies, duas respostas, e o código tem duas funções em vez de uma que estaria errada metade das vezes.
O que ninguém tinha verificado é o que acontece entre elas. A página sobrevivente levava a ligação temática para a página desaparecida.
A regra já estava registada
A função que produz essa ligação resolve um caminho de documentação para um slug de integração. O comentário dela própria dizia, antes de tudo isto acontecer, que uma ligação para um guia que não existe não é uma ligação temática mas uma ligação morta.
A regra estava lá. Estava a ser medida contra a lista errada: o conjunto das páginas de documentação que existem na fonte, em vez do conjunto que responde nesta compilação. Esses dois são o mesmo conjunto quase sempre, e o dia em que diferem é o dia em que alguma coisa está escondida.
A reparação é uma linha. Não é essa a parte interessante; a parte interessante é que uma regra correta, escrita por extenso no sítio a que pertence, não é um controlo. A prosa num comentário descreve uma intenção. Só alguma coisa que corre o pode obrigar a cumpri-la.
Um terceiro caso que nenhum rastreio poderia ter encontrado
Escrevemos uma guarda em vez de simplesmente reparar a linha: para cada slug de integração, o caminho de documentação resolvido tem de ser um que esta compilação sirva realmente. Foi provada vermelha primeiro, e comunicou as duas páginas que o rastreio tinha encontrado.
Comunicou também uma terceira: a nossa integração de servidor de cópias de segurança, que está por trás de um interruptor diferente. A página de documentação dela está escondida, e a ligação para ela era construída exatamente da mesma maneira.
A razão por que nenhum rastreador vai alguma vez encontrar essa é que a página de integração dela também está escondida. A ligação morta vivia numa página que ela própria devolve 404, portanto não há caminho de fora até àquilo que está errado. Teria vindo ao de cima no dia em que alguém ligasse esse interruptor e publicasse uma página com uma ligação partida, e os dois acontecimentos estariam a semanas de distância.
Um rastreador só consegue encontrar defeitos em páginas alcançáveis. Isso soa óbvio escrito assim e é fácil de esquecer quando um rastreio volta limpo, porque um rastreio limpo parece uma afirmação sobre o código em vez de uma afirmação sobre as páginas que por acaso estavam visíveis.
A guarda tem mais um teste que não faz nada exceto manter o primeiro honesto: afirma que mais de dez slugs resolvem mesmo para uma página de documentação. Sem ele, uma alteração que fizesse o resolvedor não devolver nada para slug nenhum produziria zero ligações mortas e zero ligações temáticas, e essas duas coisas leem-se de forma idêntica numa execução de testes verde.
A outra metade: dizer a um motor de busca que alguma coisa mudou
A mesma ronda acrescentou um canal de submissão, que é uma coisa pequena com uma surpresa lá dentro.
O protocolo é um POST que diz a vários motores de busca que um URL mudou. A posse do host prova-se servindo uma chave como ficheiro de texto na raiz. A nossa chave vem do ambiente e, quando falta, a coisa toda não faz nada e diz isso uma vez. Esse é o estado normal em desenvolvimento e em todos os testes.
Vale a pena repetir dois pormenores, porque ambos são armadilhas.
O ficheiro da chave é servido através de uma reescrita, porque uma rota dinâmica não pode ficar na raiz ao lado do segmento de língua. Uma reescrita que correspondesse a qualquer coisa ponto txt na raiz engoliria também o ficheiro robots. Duas coisas a travam: a reescrita corre na fase que só vê pedidos aos quais nenhum ficheiro verdadeiro correspondeu, e o padrão da chave exige pelo menos oito caracteres, enquanto robots tem seis e llms quatro. O limite inferior não é arrumação; é o segundo fecho.
E a submissão pendura-se na função que já sabe que o conteúdo público mudou, e não na implementação. Uma versão que só toque num ecrã do painel anunciaria de outro modo 1750 endereços como modificados de cada vez, o que é uma boa maneira de ser ignorado. Quando a tabela de preços muda, as duas rotas que geram preços são submetidas em nove línguas, o que dá 18 endereços.
A coisa que parecia uma má configuração
A primeira submissão a sério depois da implementação, com a chave de produção no sítio, devolveu 403.
O ficheiro da chave devolvia 200 de todos os sítios de onde tentámos, incluindo com um agente de utilizador de rastreador. Todos os ingredientes estavam conferidos. O passo natural seguinte é ir ver a configuração da borda, ou a reescrita, ou a ordem das fases, que é por onde se vai uma hora.
O que fizemos em vez disso foi experimentar duas coisas mais pequenas. Uma submissão de um único URL devolveu 200 de imediato. A mesma submissão em massa, um minuto depois, devolveu também 200, nos dois pontos finais.
Portanto o 403 era um efeito de primeiro contacto do lado deles, e não um defeito do nosso. O ficheiro da chave ainda não tinha sido buscado nem guardado em cache pelo serviço recetor no momento em que chegou o primeiro pedido em massa.
Registámos isso onde vive o manual de operação, porque a falha está perfeitamente desenhada para mandar alguém à caça: o código de estado diz proibido, que é uma afirmação sobre permissões, e tudo o que era permissão estava correto. Antes de investigar uma falha de autorização num primeiro pedido, faça o mesmo pedido outra vez. Não custa nada e é a hipótese mais barata da lista.
Há uma nota relacionada para quem rodar essa chave: o ficheiro é servido com uma hora de cache, por isso uma rotação precisa de uma purga ou de uma hora de paciência e, durante essa janela, o mesmo 403 quer dizer uma coisa completamente diferente.
O que registaríamos
- Duas regras corretas podem produzir um defeito na costura entre elas. Nenhum dos donos está errado e nenhum está a olhar.
- O mesmo identificador pode ter duas superfícies com duas respostas certas. Duas funções, não uma.
- Uma regra num comentário não é um controlo. A nossa estava escrita por extenso e era medida contra a lista errada.
- O que existe e o que responde são conjuntos diferentes, e divergem exatamente quando alguma coisa está escondida.
- Um rastreador só encontra defeitos em páginas alcançáveis. O nosso não conseguia ver o terceiro caso de todo.
- Uma guarda encontra a ocorrência que ainda não foi publicada. É essa a razão inteira para escrever uma em vez de reparar a linha.
- Dê a cada guarda um teste que prove que ela está a olhar. Nenhuma ligação morta e nenhuma ligação leem-se da mesma maneira.
- Um limite inferior num padrão pode ser uma fronteira de segurança. Oito caracteres é o que mantém uma reescrita longe do ficheiro robots.
- Anuncie as alterações de conteúdo a partir da coisa que sabe que o conteúdo mudou, nunca a partir da implementação.
- Repita antes de diagnosticar a falha de um primeiro pedido. Um proibido que passa a sucesso um minuto depois nunca foi sobre permissões.
Para que fique claro o que isto é: o rastreio cobriu 1776 páginas contra a produção e 1750 entradas de sitemap com 913 datas de modificação nenhuma das quais no futuro, a reparação é uma única linha guardada por três testes provados vermelhos primeiro, o caminho de submissão foi exercitado de ponta a ponta contra um ponto final simulado incluindo cinco caminhos de falha, e a varredura sobre uma compilação de produção autónoma terminou em 96 verdes. Por provar: na altura em que a reparação foi escrita estava verde sobre uma compilação de produção local e ainda não tinha sido confirmada em produção, e duas famílias de rotas no rastreio não produziram página nenhuma porque os seus registos estão vazios.
Do trabalho de plataforma na Provibr. O que uma migração de faturação consegue e não consegue levar está em quinze coisas que não viajam, uma implementação cujo passo de esquema nunca correu está em a migração que nunca correu, e outra verificação que estava verde porque nunca lá chegou está em verde porque não conseguia lá chegar.