插件导致重建期间出错

今天我尝试将我的 Discourse 安装从 2.9.0.beta9 升级到 2.9.0.beta10。但这次升级出了大问题。

  1. 我的第一次尝试是在控制台上
cd /var/discourse
sudo git pull
sudo ./launcher rebuild app

最后以这个消息中断,日志中间有这样的信息:

PG::InvalidParameterValue: ERROR:  cannot extract elements from a scalar
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:110:in `exec'

我通过启动旧的镜像(它仍然存在)成功地恢复了论坛。

  1. 我的第二次尝试是通过 Web 控制台(/admin/upgrade)。但最后也因为同样的错误而中断:ERROR: cannot extract elements from a scalar。当我回到升级面板时,它告诉我所有组件都已成功更新。但在容器重启后,服务器现在抛出了一个 HTTP 500 错误 :frowning_face:

  2. 我在一台单独的机器上进行了干净安装,从头开始。我能够安装 beta10 版本,但尝试从备份恢复时出现了完全相同的错误!

有谁能提供帮助吗?

我找到了导致它卡住的查询

INSERT INTO question_answer_votes (post_id, user_id, created_at)
	SELECT
	  X.post_id AS post_id,
	  (X.value->>'user_id')::int AS user_id,
	  (X.value->>'created_at')::timestamp AS created_at
	FROM (
	  SELECT
	    post_id,
	    jsonb_array_elements(value::jsonb) AS value
	  FROM post_custom_fields WHERE name = 'vote_history'
	) AS X
	WHERE (X.value->>'action') != 'destroy'
	ORDER BY (X.value->>'created_at')::timestamp DESC
	ON CONFLICT DO NOTHING

如果我的理解没错的话,这是因为 psql 函数 jsonb_array_elements 期望接收一个数组,但却收到了一个 NULL 值。

已经有几份关于此的报告:

我认为这可能与之前安装了 Pavilion Question/Answer 插件有关?

我会找人深入研究一下。:+1:

我们正在使用这个插件:https://github.com/angusmcleod/discourse-question-answer

  • 它似乎与 Pavilion Question and Answer 插件有关。
  • 它是 discourse/discourse-upvotes 插件的一个分支。
1 个赞

为了确认一下,您的 app.yml 中有哪些插件?

1 个赞

我看到的网站上有很多自定义帖子字段,其中包含许多经过多次编码的字符串,导致它们无法使用。

一些解决方案,按复杂程度排序:

  • 停止使用该插件(并可能切换到新的“赞成票”)
  • 删除所有这些字段
  • 删除不好的字段
  • 编辑这些字段,将数据恢复为有效的 JSON 字符串。

我看到的网站上有几年前的错误数据。这似乎是一个多年前存在的错误,现在才被发现。

可能可以编写代码来修复损坏的 JSON 字符串,但我花了 10 分钟也未能弄清楚如何做到这一点。

请参阅 Question Answer Plugin - #301 by pfaffman 获取示例。

2 个赞

我也这么想过,但快速查看了 Angus 的分支,似乎没有进行任何数据迁移。 https://github.com/angusmcleod/discourse-question-answer/compare/main...discourse:discourse-upvotes:main

正如你所说,这感觉像是旧的问答帖造成的数据污染。我也觉得奇怪的是,这现在才出现,考虑到这次迁移是 2021 年 11 月的——我猜是因为 JayJay 现在才切换到新插件?无论如何,我们会再次查看这次迁移。

1 个赞
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-solved.git
          - git clone https://github.com/unfoldingWord-dev/discourse-mermaid.git
          - git clone https://github.com/angusmcleod/discourse-question-answer.git
          - git clone https://github.com/discourse/discourse-checklist.git
          - git clone https://github.com/discourse/discourse-cakeday.git
          - git clone https://github.com/discourse/discourse-canned-replies.git
          - git clone https://github.com/discourse/discourse-footnote.git
          - git clone https://github.com/discourse/discourse-staff-notes.git
          - git clone https://github.com/discourse/discourse-graphviz.git
          - git clone https://github.com/discourse/discourse-assign.git
          - git clone https://github.com/discourse/discourse-voting.git
          - git clone https://github.com/discourse/discourse-yearly-review.git
          - git clone https://github.com/discourse/discourse-saved-searches.git

1 个赞

@nat 我根本不会切换到新插件。我仍然在使用我们已经使用了一段时间的插件集。

至少每个月,我们都会运行更新,所以版本之间不会有很大的差距。

2 个赞

除了问答问题之外,还有一个小小的“供您参考”的说明,现在还有一个可以替代预设回复的功能:

而且我相信现在还有一个官方的 Mermaid 主题组件:

1 个赞

谢谢。等我解决了最初的问题后再去查看 :smile:

1 个赞

如果我移除该插件,恢复备份仍然会导致有问题的查询运行。
因此,我需要移除该插件以及该插件使用的任何表+查询。
我将如何知道涉及的表?

您是否已注释掉该插件的行并尝试重新构建以进行确认?

2 个赞

我马上就试试。我查看了备份中的 dump.sql 文件,里面根本没有提到任何 question_answer_* 表。这让我很乐观……

1 个赞

我的暂存系统已成功!

  • 禁用插件
  • sudo ./launcher rebuild app
  • 恢复备份

我将开始处理我的在线系统。我会随时向您汇报。

1 个赞

损坏的数据位于 PostCustmField 表中。但是,如果您没有该插件,它将不会尝试将这些数据迁移到新表中。

问题不在于迁移本身,而在于过去某个时候数据被损坏了。它已经损坏了,但损坏的方式多年来一直未被发现。我认为也许每一次新的点赞都会使其进一步损坏。一个合理的修复方法可能是忽略损坏的数据,也许将其标记为损坏(也许重命名自定义字段),以便将来的迁移可以忽略它,并且有人可以根据需要手动修复它们。

2 个赞

在生产环境中也成功了。禁用了插件,然后我们继续进行。
仍然想知道为什么我没有更早遇到这个问题。正如我所说,我们每个月都会例行更新所有系统,所以我应该更早地看到这个问题。

我如何能够自己连接到 Discourse 数据库,以验证 post_custom_fields 表中的内容?

@Jaap-Jan_Swijnenburg 很抱歉您遇到了问题。

我对此持不同意见 :slight_smile:

旧的 QnA 插件使用了 标准的 Discourse 自定义字段类型转换,该转换旨在将该字段转换为 JSON。但在某些情况下(例如此情况)不起作用,这就是为什么您(理想情况下)在处理 Discourse 自定义字段时需要进行格式检查(尤其是在处理像这样相当旧的代码和数据时)。我建议 Upvotes 插件在此处需要执行此操作,这确实是当前错误来源的地方。

您可以使用数据浏览器插件来检查您在那里有什么。

好吧,我在这方面大多听从您的意见,而且我认为我们确实意见一致。我认为迁移在数据没有损坏的情况下是有效的,这一点是正确的。我们同意,如果数据损坏,它应该比现在更优雅地失败。

是的,但数据可能在几年前就已损坏(我熟悉的网站就是这种情况),但您没有注意到,因为它没有发生灾难性故障。我很确定它没有像预期的那样管理投票,但没有人注意到。

我会从 rails 进行,类似这样:

./launcher enter app
rails c

然后是这样的东西:

all_votes=PostCustomField.where(name: "vote_history")
likely_broken_votes=PostCustomField.where(name: "vote_history").where("value like '\\\"%'")

只查看 id 和数据:

all_votes.pluck(:id,:value)

获取一个 pcf:

pcf=PostCustomField.find(1234)

修复它

pcf.value='您真正想要的东西'
pcf.save

这里发生的情况是这样的:

  1. 有些人在他们的 app.yml 文件中有一个非常旧版本的问答插件,其存储库 URL 中包含我的个人 GitHub 用户名。

  2. 我多年前已将 QnA 插件转移到 paviliondev。GitHub 会在存储库转移时重定向 URL,因此包含我个人用户名的旧 URL 仍然有效。

  3. 多年后,Pavilion 将 Question Answer 插件转移到了 Discourse。Discourse 最初保留了名称 discourse-question-answer

  4. 几个月前,我创建了我自己的插件分支,托管在 discourse 中,当时它仍然被称为 discourse-question-answer

  5. 那些拥有指向包含我的个人 GitHub 帐户的 QnA 插件的非常旧链接的人,现在正在克隆托管在 discourse 中、经过显著更新的 discourse-question-answer 的新分支。换句话说,一个非常旧的链接现在指向了一个新插件的分支。尽管已经过去了这么多年,我本应该预料到这一点,对此我感到抱歉。我已经删除了那个分支。

  6. Discourse 将 discourse-question-answer 的名称更改为 discourse-upvotes。这个名称更改对您的情况 @Jaap-Jan_Swijnenburg 没有实质性影响,但这就是为什么您现在(意外地)克隆该存储库分支的原因。

  7. discourse/discourse-upvotes(以前是 discourse-question-answer)中的迁移假定 post_custom_fields 中的 value 列是 JSON 类型安全的。

  8. 该插件在 angusmcleod/discourse-question-answer(多年前)时创建的旧数据,并未被 discourse/discourse 中的 HasCustomFields 关联保存为有效的 JSON。我猜测,这些数据可能是在添加 JSON 类型检查 4 年前 之前添加的(在边缘情况下,注册为 JSON 的自定义字段中仍然可能出现无效 JSON)。

因此

  1. 当那些在 app.yml 中拥有(过时多年的)angusmcleod/discourse-question-answer URL 的人在更新他们的 Discourse 时,会克隆插件的新版本中的迁移,迁移运行,并可能产生此错误。

有几种解决方案:

  1. @Jaap-Jan_Swijnen元,在您的情况下,您只需要删除指向我旧 QnA 插件的引用,就可以重建您的站点。就是这样;仅此而已。看起来您已经做到了 :+1:

  2. 可以更新 discourse/discourse-upvotes 插件的迁移,以处理 post_custom_fieldsvalue 列中的非 JSON 值。

我想指出的是,2 也可以处理那些确实想从旧版 QnA 插件切换到 discourse-upvotes 的用户的情况。在这种情况下,迁移将运行,如果 post_custom_fieldsvalue 列中的任何条目不是有效的 JSON,迁移将失败。

5 个赞