升级错误 - rake db:migrate 在 theme_field_id 上建立索引

在最新的发行说明 (3.2.0.beta1)中,我注意到了之前没见过的 discourse-ai 插件,于是我尝试添加这个插件并同时升级我的 discourse 实例。

正如标题所述,我目前在 bootstrap 时遇到一个错误,rake db:migrate 无法在 theme_field_id 上创建唯一索引。以下是我是如何走到这一步的详细信息……

首次升级尝试(patch-package 错误)

我使用的是分体式容器安装,所以:

  • 编辑了我的 web_only.yml 文件以添加新的 discourse-ai 插件

    例如。在插件钩子中添加了额外的一行
    ## Plugins go here
    ## see https://meta.discourse.org/t/19157 for details
    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
    
  • 运行了 ./launcher bootstrap web_only

它因找不到 patch-package 的消息而报错。

Git Pull → bootstrap(pg-vector 错误)

我想确保我拥有最新的 launcher 更新,因为在重试之前进行更新总是有益的:

  • 运行 git pull 以确保我拥有最新的 launcher 相关更新
  • 再次运行 ./launcher bootstrap web_only

这次我收到了与 pg-vector 相关的错误消息。

:page_facing_up: 包含 discourse-ai 的 bootstrap 日志片段

我记下了我的 PostgreSQL 版本,以便在决定重新访问 discourse-ai 插件时有记录可查。

  • web_only:
    • 客户端:psql (PostgreSQL) 13.10 (Debian 13.10-1.pgdg110+1)
  • data:
    • 服务器:PostgreSQL 13.9 (Debian 13.9-1.pgdg110+1)

删除 discourse-ai 插件 → Bootstrap

然后我从 web_only.yml 文件中删除了 discourse-ai 插件,并再次运行了 bootstrap。

出乎意料的是,我仍然看到错误,但这次它们似乎与 rake db:migrate 无法创建唯一索引 index_javascript_caches_on_theme_field_id 有关,详细信息为:Key (theme_field_id)=(3) is duplicated。

不包含 discourse-ai 的 bootstrap 日志片段

您的帮助? :folded_hands:

因此,我在这里寻求帮助。我想先暂停一下,从社区那里获得一些见解,然后再深入研究,以防其他人遇到过这种情况。

供参考,我安装的是 3.2.0.beta1-dev (993ed10cf0 ~ 8月9日)。

虽然我不认为这与此有关,但我想提一下,我在今年年初迁移了主机……尽管从那以后我通过管理界面进行了几次 Discourse 更新。

迁移方法

据我回忆,这基本上是升级源实例到最新的 Discourse 版本,在新主机上安装 discourse,冻结源,在源上进行 Discourse 备份,在主机之间 rsync 镜像/等,在新主机上恢复备份。

对于重复索引错误,我认为如果你能 restart web_only 并从 UI 处理它们,会比在数据库中处理简单得多。尽管我以前从未在 theme_field_id 上见过这个问题。\n\n日志中 rake aborted! 上方的行提到了 discourse-voting 现在是 discourse-topic-voting。你可以尝试更新插件部分中的链接到当前版本,看看是否有帮助?

你能否澄清一下它指的是哪个资源存在重复 ID?我不确定 theme_field_id 具体指的是什么。

供记录,我并没有关闭 web_only 容器。我通常会先引导容器以尽量减少中断时间:

我会试试的。我怀疑这不会有帮助,因为我认为 GitHub 在后台会自动重定向,而这只是 Discourse 端的一个警告。:slight_smile:

如果你有一个正在运行的、安装了数据浏览器的站点,我认为你可以使用以下查询来查看它可能指的是什么:

SELECT *
FROM theme_fields
WHERE id = 3
1 个赞

我之前不知道有这个插件——真不错!我没有安装它,但我仍然能够进入数据容器并运行查询。

这真是个好线索!如果我正确理解错误消息的话,我认为问题不在于 theme_fields 表,因为那个表没有 theme_field_id。我没有检查源代码,但我猜测 add_index() 的第一个参数是表名,第二个参数是列名。

基于此,看起来问题出在 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})

所以我检查了那个表的结构,它有 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

我能够查询那个表(缩短了 content 字段以便我能读懂),并且可以看到重复项。但我不知道这些重复项意味着什么。

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

内容看起来很熟悉,所以我进入了 Customize → Theme → My Theme → Common → Head,做了一个小的修改并保存,我可以看到其中一个条目被更新了,而另一个仍然是旧的……

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)

同样,我不知道这些重复项意味着什么,是否可以安全地删除“旧的”一个,或者是否有其他方法可以“重建”缓存来清理这些?

老实说,到目前为止我在这方面是0/2,所以这可能不是我能提供最多信息的来源。:slight_smile:

之前有几个关于 index_tags_on_name 发生类似情况的主题,看看是否有用?例如:

1 个赞

重建数据容器。ai 插件需要一个您还没有的扩展。

感谢您的帮助!看来您把我引向了正确的方向。:star_struck:

我使用 pg_dump 备份了表,删除了旧的重复条目,然后引导成功完成了。:+1:

感谢确认!我猜到我可能需要更新数据容器(或者安装 pgvector)。我一直推迟这样做,因为我不想处理停机时间。

从 discourse-ai 线程来看,PG15 似乎即将推出,所以我可能再等一会儿。

看起来 pgvector 依赖项可能是为了 Embeddings 功能,而我并不打算使用它,但不幸的是,听起来它似乎是捆绑在一起的。我主要只是想玩一些 OpenAI / ChatGPT 的魔改重写功能,所以也许这是等到下一个大型数据容器更新之前再等待的一个理由。:slight_smile:

1 个赞

你想等也可以,但单容器用户(这是绝大多数自托管用户)在每次升级时都可能会升级他们的 postgres,所以除了多几分钟的停机时间外,没有太多理由等待。在数据库重建之后,你需要重建(或者可能只是销毁然后启动)web_only 容器。

1 个赞

这是主要原因。即使只有几分钟,如果不是关键的,我也宁愿尽量减少它。

话虽如此,但考虑到潜在的停机时间,我可能应该暂缓使用 beta 插件。:stuck_out_tongue:

我大致关注了一些关于“零停机时间”升级的讨论。也许只是回顾近期历史的乐观想法,但感觉在过去一年里,我能够对大多数更新使用 /admin/upgrade,所以我暂时专注于更关键的项目,对零停机时间的方法失去了兴趣。

当我一月份迁移到更大的主机时,它是“零停机时间”,因为用户可以继续访问网站上的内容,但在我们过渡期间有一段短暂的时间是只读的。我想,如果我真的想在下一次大的 data 升级期间尽量减少停机时间,我可以使用这种方法来处理重大的 data 容器升级。

附注。多年来,我在这里的社区里读了大量你的帖子。感谢你为支持社区所做的所有努力!:star2:

确实如此!我已经很久没有为我的“需要时重建”的客户进行升级了。对于像您这样的网站,我的仪表板将在新容器启动后(如果您的现有容器设置了首次运行时不运行那些迁移)执行重建并执行升级后迁移。

1 个赞