Erro de Upgrade - rake db:migrate índice em theme_field_id

Nas notas de lançamento mais recentes (3.2.0.beta1), notei o plugin discourse-ai que eu não tinha visto antes, então tentei adicionar este plugin e atualizar minha instância do Discourse ao mesmo tempo.

Como mencionado no título, estou vendo um erro no bootstrap onde o rake db:migrate falha ao criar um índice único em theme_field_id. Aqui estão alguns detalhes sobre como cheguei a esse ponto, no entanto…

Tentativa Inicial de Atualização (erro do patch-package)

Estou executando uma instalação de contêiner dividida, então eu:

  • Editei meu web_only.yml para adicionar o novo plugin discourse-ai

    ex. Adicionada uma linha extra aos hooks de plugins
    ## Plugins vão aqui
    ## veja https://meta.discourse.org/t/19157 para detalhes
    hooks:
      after_code:
        - exec:
            cd: $home/plugins
            cmd:
              - sudo -E -u discourse git clone https://github.com/discourse/docker_manager.git
              - sudo -E -u discourse git clone https://github.com/discourse/discourse-voting.git
              - sudo -E -u discourse git clone https://github.com/discourse/discourse-ai.git
    
  • Executei ./launcher bootstrap web_only

Ele falhou com uma mensagem sobre patch-package não ser encontrado.

Git Pull → bootstrap (erro do pg-vector)

Pensei em garantir que tinha as últimas atualizações do launcher, pois não faria mal antes de tentar novamente:

  • Executei um git pull para garantir que tinha as últimas atualizações relacionadas ao launcher
  • Executei ./launcher bootstrap web_only novamente

Desta vez, recebi mensagens de erro relacionadas ao pg-vector.

:page_facing_up: Trecho do log do bootstrap com discourse-ai

Anotei minhas versões do PostgreSQL para ter em meus registros quando decidisse revisitar o plugin discourse-ai.

  • web_only:
    • cliente: psql (PostgreSQL) 13.10 (Debian 13.10-1.pgdg110+1)
  • data:
    • servidor: PostgreSQL 13.9 (Debian 13.9-1.pgdg110+1)

Remover Plugin discourse-ai → Bootstrap

E então removi o plugin discourse-ai do arquivo web_only.yml e executei um bootstrap novamente.

Para minha surpresa, eu ainda estava vendo erros, mas desta vez eles parecem estar relacionados ao rake db:migrate não conseguir criar um índice único index_javascript_caches_on_theme_field_id com o detalhe: Chave (theme_field_id)=(3) duplicada.

:page_facing_up: Trecho do log do bootstrap sem discourse-ai

Sua ajuda? :folded_hands:

É por isso que estou aqui procurando ajuda. Pensei em fazer uma pausa e obter algumas informações da comunidade antes de me aprofundar mais, caso alguém mais tenha visto isso antes.

Para referência, tenho a versão 3.2.0.beta1-dev (993ed10cf0 ~ 9 de agosto) instalada.

E embora eu não ache que esteja relacionado a isso, acho que não faz mal mencionar que migrei entre máquinas host no início deste ano… embora eu tenha feito várias atualizações do Discourse através da interface de administração desde então.

Abordagem de migração

Pelo que me lembro, isso foi basicamente atualizar a instância de origem para a versão mais recente do Discourse, instalar o Discourse no novo host, congelar a origem, fazer um backup do Discourse na origem, rsync imagens/etc entre os hosts, restaurar o backup no novo host.

Para os erros de índice duplicado, acho que se você puder reiniciar web_only e lidar com eles a partir da UI, é muito mais simples do que fazer isso no banco de dados. Embora eu não ache que já tenha visto um em theme_field_id antes.
A linha logo acima de rake aborted! nos logs menciona que discourse-voting agora é discourse-topic-voting. Você poderia tentar atualizar o link na seção de plugins para o atual e ver se isso ajuda?

Você pode esclarecer qual recurso está se referindo como tendo um ID duplicado? Eu não tinha certeza exatamente a que theme_field_id se refere.

Para constar, eu não tinha desligado o contêiner web_only. Eu geralmente inicializo o contêiner primeiro para minimizar a janela de inatividade:

Vou tentar. Suspeito que não ajudará, pois eu pensaria que o GitHub estaria redirecionando as coisas silenciosamente nos bastidores e é apenas um aviso do lado do Discourse. :slight_smile:

Se você tem um site em funcionamento com o explorador de dados instalado, acho que você poderá dar uma olhada no que isso pode estar se referindo usando esta consulta:

SELECT *
FROM theme_fields
WHERE id = 3
1 curtida

Não estava ciente desse plugin - que legal! Eu não o tenho instalado, mas consigo entrar no contêiner de dados e executar consultas.

Essa é uma ótima pista! Se estou lendo a mensagem de erro corretamente, acho que não está na tabela theme_fields, pois essa tabela em particular não tem um theme_field_id. Não verifiquei o código-fonte, mas me arriscaria a dizer que o primeiro argumento para add_index() é o nome da tabela e o segundo é a coluna.

Com base nisso, parece que seria a tabela javascript_caches.

== 20230817174049 EnsureJavascriptCacheIsUniquePerTheme: migrating ===========
-- remove_index(:javascript_caches, :theme_id)
   -> 0.0208s
-- add_index(:javascript_caches, :theme_id, {:unique=>true})
   -> 0.0079s
-- remove_index(:javascript_caches, :theme_field_id)
   -> 0.0026s
-- add_index(:javascript_caches, :theme_field_id, {:unique=>true})

Então, verifiquei a estrutura dessa tabela e ela tem a coluna theme_field_id:

discourse=# \d javascript_caches
                                          Table "public.javascript_caches"
     Column     |            Type             | Collation | Nullable |                    Default
----------------+-----------------------------+-----------+----------+-----------------------------------------------
 id             | bigint                      |           | not null | nextval('javascript_caches_id_seq'::regclass)
 theme_field_id | bigint                      |           |          |
 digest         | character varying           |           |          |
 content        | text                        |           | not null |
 created_at     | timestamp without time zone |           | not null |
 updated_at     | timestamp without time zone |           | not null |
 theme_id       | bigint                      |           |          |
 source_map     | text                        |           |          |
Indexes:
    "javascript_caches_pkey" PRIMARY KEY, btree (id)
    "index_javascript_caches_on_digest" btree (digest)
    "index_javascript_caches_on_theme_field_id" btree (theme_field_id)
    "index_javascript_caches_on_theme_id" btree (theme_id)
Check constraints:
    "enforce_theme_or_theme_field" CHECK (theme_id IS NOT NULL AND theme_field_id IS NULL OR theme_id IS NULL AND theme_field_id IS NOT NULL)
Foreign-key constraints:
    "fk_rails_58f94aecc4" FOREIGN KEY (theme_id) REFERENCES themes(id) ON DELETE CASCADE
    "fk_rails_ed33506dbd" FOREIGN KEY (theme_field_id) REFERENCES theme_fields(id) ON DELETE CASCADE

Consegui consultar essa tabela (com os campos de conteúdo encurtados para que eu pudesse realmente ler) e consigo ver os duplicados. Mas não tenho certeza qual é a implicação desses duplicados.

discourse=# select id, theme_field_id, digest, substring(content from 1 for 64) as content_64, created_at, updated_at, theme_id, substring(source_map from 1 for 64) as source_64 from javascript_caches where theme_field_id = 3;
 id | theme_field_id |                  digest                  |                            content_64                            |         created_at         |         updated_at         | theme_id |                            source_64
----+----------------+------------------------------------------+------------------------------------------------------------------+----------------------------+----------------------------+----------+------------------------------------------------------------------
  1 |              3 | d0b6ec642d5649064ff0501cadc775a9217b16e0 | "define"in window&&define("discourse/theme-3/initializers/theme- | 2019-02-25 01:26:56.606537 | 2023-08-18 20:47:19.596923 |          | {"version":3,"sources":["discourse/initializers/theme-field-3-co
  2 |              3 | 7fd74ecf4448afccdbcd9ccde87acddb4ec6f514 | "define"in window&&define("discourse/theme-3/initializers/theme- | 2019-02-25 01:26:58.228209 | 2023-08-18 20:50:41.049209 |          | {"version":3,"sources":["discourse/initializers/theme-field-3-co

O conteúdo parecia familiar, então fui em Customize → Theme → My Theme → Common → Head, fiz uma pequena alteração e salvei, e consigo ver que uma das entradas foi atualizada e uma delas permanece antiga…

discourse=# select id, theme_field_id, digest, substring(content from 1 for 64) as content_64, created_at, updated_at, theme_id, substring(source_map from 1 for 64) as source_64 from javascript_caches where theme_field_id = 3;
 id | theme_field_id |                  digest                  |                            content_64                            |         created_at         |         updated_at         | theme_id |                            source_64
----+----------------+------------------------------------------+------------------------------------------------------------------+----------------------------+----------------------------+----------+------------------------------------------------------------------
  2 |              3 | 7fd74ecf4448afccdbcd9ccde87acddb4ec6f514 | "define"in window&&define("discourse/theme-3/initializers/theme- | 2019-02-25 01:26:58.228209 | 2023-08-18 20:50:41.049209 |          | {"version":3,"sources":["discourse/initializers/theme-field-3-co
  1 |              3 | 7f4132b1f9ced1b90b8f8fc24812cc11e81fea8d | "define"in window&&define("discourse/theme-3/initializers/theme- | 2019-02-25 01:26:56.606537 | 2023-09-13 21:56:56.312263 |          | {"version":3,"sources":["discourse/initializers/theme-field-3-co
(2 rows)

Novamente, não tenho certeza qual é a implicação desses duplicados, se é seguro excluir o ‘antigo’, ou se há alguma outra maneira de ‘reconstruir’ os caches que limparia isso?

Para ser honesto, estou 0/2 até agora, então provavelmente não sou a melhor fonte de informação para este. :slight_smile:

Existem alguns tópicos anteriores onde algo semelhante aconteceu para index_tags_on_name, se eles puderem ser úteis? por exemplo.

1 curtida

Reconstrua seu contêiner de dados. O plugin de IA requer uma extensão que você ainda não possui.

Agradeço sua ajuda! Parece que você me guiou pelo caminho certo. :star_struck:

Fiz um backup da tabela com pg_dump, excluí a entrada duplicada antiga e o bootstrap foi concluído com sucesso. :+1:

Obrigado pela confirmação! Achei que talvez precisasse atualizar o contêiner de dados (ou de outra forma instalar o pgvector). Estava adiando fazer isso, pois não queria lidar com o tempo de inatividade.

Pelo tópico do discourse-ai, parece que o PG15 está a caminho, então talvez eu espere um pouco por ele.

Parece que a dependência do pgvector pode ser para o recurso de Embeddings, que eu não planejava usar, mas infelizmente parece que tudo está empacotado junto. Eu principalmente queria brincar com alguns dos recursos de reescrita mágica do OpenAI / ChatGPT, então talvez mais um motivo para esperar até a próxima grande atualização do contêiner de dados. :slight_smile:

1 curtida

Você pode esperar se quiser, mas as pessoas de contêiner único (que é a grande maioria dos auto-hospedeiros) atualizam seu postgres potencialmente toda vez que fazem uma atualização, então não há muita razão para esperar além de alguns minutos extras de inatividade. Você precisará reconstruir (ou talvez apenas destruir e iniciar) o contêiner web_only após a reconstrução do banco de dados.

1 curtida

Esse é o principal motivo. Mesmo que sejam apenas alguns minutos, prefiro minimizar se não for crítico.

Nesse sentido, eu provavelmente deveria evitar usar um plugin beta apenas pelo potencial de inatividade. :stuck_out_tongue:

Eu acompanhei de forma superficial algumas das discussões sobre atualizações de ‘inatividade zero’. Talvez sejam apenas óculos cor-de-rosa olhando para o passado recente, mas sinto que consegui usar /admin/upgrade para a maioria das atualizações no último ano, então tenho me concentrado em projetos mais críticos por enquanto e perdi o interesse na abordagem de inatividade zero.

Quando migrei para um host maior em janeiro, foi ‘inativo zero’ no sentido de que os usuários podiam continuar acessando o conteúdo do site, mas houve um breve período em que as coisas estavam somente leitura enquanto transicionávamos. Suponho que eu poderia usar essa abordagem para uma grande atualização de contêiner data se eu realmente quisesse minimizar o tempo de inatividade durante a próxima grande atualização de data.

PS. Li muitos dos seus posts na comunidade aqui ao longo dos anos. Obrigado por todos os seus esforços em apoiar a comunidade! :star2:

Realmente parece! Não faço uma atualização para meus clientes de “reconstrução quando você precisar” há um bom tempo. Para sites como o seu, meu painel fará a reconstrução e as migrações pós-atualização após o lançamento do novo contêiner (se o seu contêiner existente tiver essas migrações configuradas para não serem executadas na primeira vez).

1 curtida