TL;DR: Cometi um erro em uma atualização e estamos buscando ajuda
Com o Home Assistant, usamos o Discourse para impulsionar nossa comunidade. Operamos com o método discourse_docker em uma instância EC2 na AWS.
Sendo um projeto de código aberto, a manutenção do fórum acabou ficando de lado e acabamos com uma versão antiga, atualizada pela última vez no início de 2019.
Para piorar, em uma atualização anterior, travamos o Postgres na versão 9.5 porque não tínhamos espaço em disco suficiente para atualizar para o Postgres 10. Nunca resolvemos esse problema.
Também fizemos uma vez uma alteração no modelo do Cloudflare e a commitamos no repositório, o que impediu que a branch discourse_docker se atualizasse para a versão mais recente.
Ontem decidimos prosseguir com a atualização…
Quando o banco de dados estava sendo migrado, encontramos um problema: foi usada uma sintaxe incompatível com a versão 9.5:
== 20200429095034 AddTopicThumbnailInformation: migrating =====================
-- execute("ALTER TABLE posts\nADD COLUMN IF NOT EXISTS image_upload_id bigint\n")
Percebemos rapidamente o problema de ter travado na versão 9.5. Então decidimos migrar para o Postgres 10. Isso não funcionou e recebemos o erro:
I, [2020-06-12T00:30:55.448351 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 10
WARNING: Upgrading PostgresSQL would require an addtional 89M of disk space
Please free up some space, or expand your disk, before continuing.
Tínhamos 47 GB disponíveis, então isso era estranho. Percebemos então que o discourse_docker estava desatualizado e o atualizamos para a versão mais recente. Surpresa: o Postgres 12 acabara de chegar.
Após executar o rebuild novamente, desta vez recebemos este erro:
I, [2020-06-12T00:41:17.378129 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 12
WARNING: Upgrading PostgresSQL would require an addtional 92G of disk space
Please free up some space, or expand your disk, before continuing.
Isso exige um pouco mais de espaço, mas tudo bem. Vamos apenas aumentar nosso espaço em disco para 300 GB e executar novamente.
Desta vez, o pg_upgrade falhou durante a migração:
Restoring database schemas in the new cluster
template1
discourse
*failure* Consult the last few lines of "pg_upgrade_dump_16384.log" for the probable cause of the failure. Failure, exiting
Ao examinar o arquivo pg_upgrade_dump_16384.log, vimos o seguinte erro:
pg_restore: creating VIEW "postgres_exporter.pg_stat_activity"
pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 721; 1259 678554 VIEW pg_stat_activity postgres
pg_restore: [archiver (db)] could not execute query: ERROR: column pg_stat_activity.waiting does not exist
LINE 27: "pg_stat_activity"."waiting",
^
Command was:
-- For binary upgrade, must preserve pg_type oid
SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('678556'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_type array oid
SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('678555'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_class oids
SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('678554'::pg_catalog.oid);
CREATE VIEW "postgres_exporter"."pg_stat_activity" AS
SELECT "pg_stat_activity"."datid",
"pg_stat_activity"."datname",
"pg_stat_activity"."pid",
"pg_stat_activity"."usesysid",
"pg_stat_activity"."usename",
"pg_stat_activity"."application_name",
"pg_stat_activity"."client_addr",
"pg_stat_activity"."client_hostname",
"pg_stat_activity"."client_port",
"pg_stat_activity"."backend_start",
"pg_stat_activity"."xact_start",
"pg_stat_activity"."query_start",
"pg_stat_activity"."state_change",
"pg_stat_activity"."waiting",
"pg_stat_activity"."state",
"pg_stat_activity"."backend_xid",
"pg_stat_activity"."backend_xmin",
"pg_stat_activity"."query"
FROM "pg_stat_activity";
Ah, merda.
Foi então que decidimos dar alguns passos para trás. Poderíamos apenas colocar o fórum no ar novamente e colocá-lo em modo somente leitura enquanto resolvemos esse problema de backup? Conseguimos fazer isso corrigindo alguns problemas de permissão tanto para o postgres quanto para o redis, e o fórum voltou ao ar na versão antiga. Nem tudo funciona; por exemplo, ao acessar admin → usuário → grupos, recebemos este erro:
NoMethodError (undefined method `automatic_membership_retroactive' for #<Group:0x00007fcaca3045e8>)
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
Mas o resto parece estar funcionando.
Neste ponto, decidimos que, como tivemos que usar chown para voltar a uma instância funcional, deveríamos simplesmente iniciar uma nova instância e importar nosso backup.
Então iniciamos uma nova instância EC2, seguimos as instruções de início do discourse_docker e iniciamos nossa importação. Em seguida, encontramos um problema estranho: não foi possível criar um índice porque os dados não correspondiam aos requisitos de unicidade do índice:
ERROR: could not create unique index "index_incoming_domains_on_name_and_https_and_port"
DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
EXCEPTION: psql failed: DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
/var/www/discourse/lib/backup_restore/database_restorer.rb:95:in `restore_dump'
Mas quando entramos no console do Rails da nossa instância em execução, não era um duplicado:
[7] pry(main)> IncomingDomain.where(name: "homeassistant.home")
=> [#<IncomingDomain:0x000055e5cabc3760 id: 8648, name: "homeassistant.home", https: false, port: 8123>]
É aí que estamos agora. E estamos meio perdidos.
- Temos uma instância em execução com um banco de dados ruim em comparação ao código Ruby, que não consegue migrar para versões mais recentes do Postgres
- Temos um backup que não pode ser importado em uma nova instância
Exploramos a possibilidade de migrar para um Discourse hospedado pago, mas como temos 3 milhões de visualizações de página e um milhão de postagens, o preço corporativo é um compromisso muito grande para nós.
Então precisamos encontrar uma saída. Preferencialmente, poderíamos importar nosso backup, mas migrar nossa instância antiga também funcionaria.
Alguém tem alguma ideia? Não nos importamos em pagar alguém para nos ajudar também.