Atualizações sem tempo de inatividade

Hello there,

We are wondering if zero downtime upgrades are possible. We are using the discourse_docker installation using separate web and data containers, so the issue is more around the old application code (v2.1) running against a migrated v2.3.0 database schema. This happens between the time we bootstrap the image (which will run the migrations) and the moment the web servers get restarted (updated) to run the upgraded image. Are there any recommendation for this?

Realizamos a atualização com sucesso há alguns meses. Estou compartilhando nossa experiência aqui para quem possa ter a mesma pergunta no futuro.

O Discourse oferece suporte parcial a atualizações sem tempo de inatividade por meio de migrações pós-implementação. O processo geral, conforme entendemos, pode ser dividido em duas etapas.

ETAPA 1: Atualize para a nova versão e execute migrações seguras:

  • Atualize todos os seus plugins e temas para que sejam compatíveis com a nova versão. (Isso pode exigir bastante trabalho, dependendo da sua configuração).
  • Gere seu web_only.yml contendo:
    version: <NOVA_VERSION>
    SKIP_POST_DEPLOYMENT_MIGRATIONS=1
  • Inicialize (./launcher bootstrap web_only)
  • Reinicie seus servidores

ETAPA 2: Execute a migração pós-implementação (migrações de alto risco, como exclusão de colunas e tabelas, etc.). Nesta etapa, o processo já deve ser seguro, pois todos os servidores estão executando a nova versão do código e não devem depender dos dados que serão excluídos:

  • Gere seu web_only.yml com:
    version: <NOVA_VERSION>
    SKIP_POST_DEPLOYMENT_MIGRATIONS=0
  • Inicialize (./launcher bootstrap web_only)
  • Reinicie seus servidores

Complicações:
Decidimos executar a ETAPA 1 e a ETAPA 2 em datas diferentes, o que causou alguns problemas. Houve uma grande refatoração no modelo de enquetes entre as versões 2.1 e 2.3. Parece que, inicialmente, a maioria dos dados de enquetes era armazenada como um objeto JSON na tabela post_custom_fields. Até a versão 2.3, eles foram movidos para sua própria tabela polls. Isso exigiu uma migração de dados que foi realizada como parte das migrações pós-implementação (ETAPA 2).

Nosso problema específico foi que, logo após a migração para a versão 2.3, as enquetes criadas antes da atualização ficaram quebradas, provavelmente porque o código que as renderizava assumia o novo modelo de dados. Alguns usuários notaram isso e tentaram atualizar manualmente as enquetes pela interface, criando registros na nova tabela polls. Esses registros, como descobrimos com tristeza mais tarde, desencadeavam uma restrição de unicidade do PostgreSQL durante o processo de inicialização, efetivamente interrompendo-o.

Para contornar isso, decidimos aplicar um patch que pulava uma migração específica de enquetes se ela já existisse no banco de dados. Essa não foi uma solução perfeita, pois alguém poderia perder dados de post_custom_fields que nunca seriam migrados para esses posts. No nosso caso, porém, isso ainda foi um bom compromisso, já que o número de casos era muito baixo em nosso sistema (2 instâncias que conseguimos observar) e nos permitiu executar o processo de inicialização. Agora, testar e aplicar o patch levantou mais duas perguntas:

  • Como testamos a alteração antes de enviar o PR?
    Queríamos testar nosso código nas mesmas condições em que seria executado na realidade, o que significava testá-lo contra o processo de inicialização. Isso não é tão simples quanto testar alterações de código em tempo de execução, que você pode fazer executando o aplicativo Discourse standalone localmente.

  • Como incorporamos as alterações em nosso sistema?
    Não queríamos esperar até que o patch chegasse a um lançamento oficial do Discourse, o que pode ser um processo demorado e basicamente nos forçaria a fazer outra atualização. Já tínhamos clientes reclamando de enquetes existentes e, quanto mais esperávamos, maiores eram as chances de os clientes modificarem manualmente as enquetes, agravando os problemas de integridade dos dados.

Então, encontramos uma maneira de testar as alterações que estávamos introduzindo, alterando a origem do repositório que o script de inicialização usa. Isso exigiu alguns testes e erros, pois não somos muito experientes com pups e outras ferramentas relacionadas a esse processo. No final, fizemos algo como isso.

Isso nos permitiu verificar se nossa correção funcionou conforme o esperado. Também conseguimos inicializar uma nova imagem em produção a partir de nossa própria versão modificada do Discourse contendo o patch, sem precisar esperar por um lançamento oficial do Discourse.