Os Sites Estáticos Continuam no Ar Enquanto Republicam
Republicar um site estático no Mythex apagava antes os ficheiros em produção e só depois enviava a nova compilação, por isso, durante o envio, alguns visitantes recebiam uma página 404 ou uma página cujos scripts estavam em falta. Um envio falhado podia deixar o site vazio ou meio novo. Agora a nova compilação é escrita por cima da antiga, com as páginas por último, e os restos são removidos alguns minutos depois. Uma segunda correção faz com que uma republicação apareça em segundos em vez de um minuto — ou, para ficheiros como um logótipo, até um dia.
Como um site estático é servido
Um site estático é apenas ficheiros: páginas HTML, JavaScript, CSS, imagens. Quando publicas um no Mythex, nós compilamos, enviamos o resultado para armazenamento de objetos numa pasta do teu site e servimo-lo através de uma rede de borda — servidores próximos dos teus visitantes que vão buscar os ficheiros ao armazenamento e guardam cópias durante algum tempo. (Se isto for novo para ti, o nosso guia sobre o que é uma CDN explica a ideia.)
Havia duas coisas erradas: a ordem pela qual uma republicação alterava os ficheiros e durante quanto tempo as cópias antigas eram mantidas.
Problema 1: o envio esvaziava o site primeiro
Uma republicação apagava tudo na pasta do site e só depois enviava a nova compilação. Durante o tempo que o envio demorava — 12 segundos para um site de 250 ficheiros no nosso teste local — um visitante cujo pedido não estivesse já em cache na borda recebia um 404, ou uma página HTML cujos scripts devolviam 404.
Um envio falhado era pior. A pasta já estava vazia, e numa das duas vias de envio o novo index.html podia ficar gravado antes do ficheiro que falhou. Uma publicação reportada como falhada podia deixar um site meio novo em produção.
A correção: escrever por cima, páginas por último, limpar depois
- Não apagar primeiro. A nova compilação é enviada por cima da antiga.
- Recursos antes das páginas. Uma página indica os scripts e estilos de que precisa, por isso as páginas sobem por último. Até as novas páginas chegarem, os visitantes recebem a página antiga, que indica os recursos antigos, que ainda lá estão. Quando chegam, os recursos novos de que precisam já estão no lugar.
- Remover os restos mais tarde. Antes do envio, listamos do que o site é feito. Três minutos depois de um envio bem-sucedido, tudo o que estiver nessa lista e que a nova compilação não tenha reescrito é apagado. Três minutos é mais do que os 60 segundos durante os quais uma página pode estar em cache na borda e no browser, por isso um visitante que ainda tenha a página antiga consegue encontrar os recursos que ela referencia.
- Na dúvida, não apagar nada. Se a listagem antes do envio falhar, não se remove nada. Os ficheiros que sobram são inofensivos, e a publicação seguinte limpa-os. Apagar sem saber o que lá estava é a forma como um site acaba vazio.
Um envio falhado deixa agora o site anterior exatamente como estava.
Testámos isto de ponta a ponta localmente, com o script de envio real, a rota de envio real e o serviço de armazenamento real, e com visitantes a chegar com a cache de borda vazia. Com o código antigo, 55 de 91 visitas ficaram quebradas durante uma republicação e 61 de 92 durante uma falhada. Com o código novo, 0 ficaram quebradas em cerca de 3.500 visitas, cobrindo as duas vias de envio, um envio falhado e a publicação seguinte — e foram removidos exatamente os ficheiros que sobravam.
Problema 2: uma republicação demorava a aparecer
Mesmo quando o envio corria bem, as alterações demoravam a surgir. A borda guardava a sua cópia de uma página durante 60 segundos e de todos os outros ficheiros durante um dia, e dizia aos browsers para fazerem o mesmo. Ficheiros com nome fixo — logo.png, um tipo de letra, qualquer coisa de uma pasta public/ — podiam mostrar a versão antiga até um dia depois de uma republicação.
A correção: cópias de ficheiros dentro da compilação
Quando a borda pergunta à nossa API onde um site está, a resposta inclui agora um marcador de compilação que muda sempre que uma publicação entra em produção. A borda guarda as suas cópias sob esse marcador. Uma publicação passa, portanto, a ser um conjunto totalmente novo de chaves de cache assim que expira a consulta de 30 segundos da borda. As cópias antigas simplesmente deixam de ser encontradas, por isso a borda pode manter cópias durante um dia sem nunca servir uma que tenha sido substituída pela publicação seguinte.
Os browsers recebem duas regras diferentes:
- Saída de compilação com hash — ficheiros como
assets/index-CzLcxDO8.js, cujo nome muda sempre que o conteúdo muda — fica em cache durante um ano e marcado como imutável. Sob esse nome nunca pode estar desatualizado. - Tudo o resto — páginas e ficheiros de nome fixo como um logótipo — é marcado como
no-cache, o que significa "verificar antes de usar". Se nada mudou, a resposta é um304 Not Modifiedminúsculo, sem corpo, agora que respeitamos a verificaçãoIf-None-Matchdo browser.
Distinguir as duas coisas exige cuidado: um ficheiro copiado de public/assets/ mantém o seu próprio nome, e pôr assets/logo.png em cache durante um ano fixaria o logótipo antigo durante um ano. Por isso, um ficheiro só conta como tendo hash se estiver numa pasta de saída de compilação e o nome tiver um segmento que pareça um hash, e não uma palavra comum.
Localmente, a nova página e o novo logótipo ficaram visíveis 6 segundos depois de a publicação entrar em produção. Antes, eram 60 segundos para a página e um dia para o logótipo.
Duas correções menores pelo caminho
- Páginas em branco a partir de pedidos HEAD. Um pedido
HEADpede os cabeçalhos de uma página sem o corpo. Estávamos a pôr em cache essas respostas vazias, por isso o visitante seguinte a essa página recebia uma página em branco. As respostasHEADjá não são guardadas em cache. - Uma página real para "aqui não há nada". Um endereço sem app recebia antes um texto simples "This published app is offline or the link was not found" com o código de erro 502. Agora recebe uma página adequada, "There's no app here", com o estado 404 e uma forma de voltar ao Mythex para o dono. Domínios personalizados desconhecidos recebem a mesma página.
O que tirámos disto
- A ordem faz parte da correção. Os mesmos ficheiros enviados por outra ordem são a diferença entre um site partido e um site a funcionar.
- Apaga tarde, e só o que conheces. Limpar com uma listagem feita antes do envio é seguro; esvaziar uma pasta e esperar que o envio termine não é.
- Põe em cache por versão, não por tempo. Os tempos de expiração são um palpite sobre quando o conteúdo muda. Uma chave que muda com a compilação é um facto.
Relacionado: a tua app publicada agora continua no ar enquanto a republicas. Mais sobre publicação na documentação.