2.7.0.beta2 升级失败,出现 ERROR: duplicate key

我从 2.7.0.beta1 升级时遇到了以下错误信息:

2021-01-22 20:16:22.015 UTC [4055] discourse@discourse LOG:  duration: 75335.241 ms  statement: UPDATE notifications SET processed = true
2021-01-22 20:16:23.792 UTC [4055] discourse@discourse LOG:  duration: 1776.591 ms  statement: ALTER TABLE "notifications" ALTER COLUMN "processed" SET NOT NULL
2021-01-22 20:16:25.198 UTC [4055] discourse@discourse LOG:  duration: 1323.298 ms  statement: CREATE  INDEX  "index_notifications_on_processed" ON "notifications"  ("processed")
2021-01-22 20:16:25.458 UTC [4055] discourse@discourse LOG:  duration: 241.063 ms  statement: CREATE TABLE "user_notification_schedules" ("id" bigserial primary key, "user_id" integer NOT NULL, "enabled" boolean DEFAULT FALSE NOT NULL, "day_0_start_time" integer NOT NULL, "day_0_end_time" integer NOT NULL, "day_1_start_time" integer NOT NULL, "day_1_end_time" integer NOT NULL, "day_2_start_time" integer NOT NULL, "day_2_end_time" integer NOT NULL, "day_3_start_time" integer NOT NULL, "day_3_end_time" integer NOT NULL, "day_4_start_time" integer NOT NULL, "day_4_end_time" integer NOT NULL, "day_5_start_time" integer NOT NULL, "day_5_end_time" integer NOT NULL, "day_6_start_time" integer NOT NULL, "day_6_end_time" integer NOT NULL)
2021-01-22 20:16:25.560 UTC [4055] discourse@discourse LOG:  duration: 100.868 ms  statement: CREATE  INDEX  "index_user_notification_schedules_on_user_id" ON "user_notification_schedules"  ("user_id")
2021-01-22 20:16:25.782 UTC [4055] discourse@discourse LOG:  duration: 142.180 ms  statement: CREATE  INDEX  "index_do_not_disturb_timings_on_scheduled" ON "do_not_disturb_timings"  ("scheduled")
2021-01-22 20:16:26.414 UTC [4055] discourse@discourse LOG:  duration: 361.514 ms  statement: UPDATE users
	SET locale = 'en_GB'
	WHERE locale = 'en'
	
2021-01-22 20:16:26.656 UTC [4055] discourse@discourse LOG:  duration: 132.778 ms  statement: UPDATE theme_translation_overrides
	SET locale = 'en_GB'
	WHERE locale = 'en'
	
2021-01-22 20:16:42.745 UTC [4055] discourse@discourse ERROR:  duplicate key value violates unique constraint "index_users_on_username"
2021-01-22 20:16:42.745 UTC [4055] discourse@discourse DETAIL:  Key (username)=(DaveW) already exists.
2021-01-22 20:16:42.745 UTC [4055] discourse@discourse STATEMENT:  UPDATE users
	SET locale = 'en'
	WHERE locale = 'en_US'
	
rake aborted!
StandardError: 发生错误,此迁移及后续所有迁移已取消:

PG::UniqueViolation: 错误:重复键值违反了唯一约束 "index_users_on_username"
DETAIL: 键 (username)=(DaveW) 已存在。

然后在输出末尾:

I, [2021-01-22T20:16:42.805286 #1] INFO -- : 终止异步进程

I, [2021-01-22T20:16:42.805333 #1] INFO -- : 向 HOME=/var/lib/postgresql USER=postgres exec chpst -u postgres:postgres:ssl-cert -U postgres:postgres:ssl-cert /usr/lib/postgresql/13/bin/postmaster -D /etc/postgresql/13/main pid: 49 发送 INT 信号

I, [2021-01-22T20:16:42.805381 #1] INFO -- : 向 exec chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf pid: 166 发送 TERM 信号

166:signal-handler (1611346602) 收到 SIGTERM 信号,计划关闭...

2021-01-22 20:16:42.805 UTC [49] LOG: 收到快速关闭请求

2021-01-22 20:16:42.835 UTC [49] LOG: 中止所有活跃事务

2021-01-22 20:16:42.857 UTC [49] LOG: 后台工作进程 "logical replication launcher"(PID 58)以退出代码 1 退出

166:M 22 Jan 2021 20:16:42.876 # 用户请求关闭...

166:M 22 Jan 2021 20:16:42.876 * 在退出前保存最终的 RDB 快照。

166:M 22 Jan 2021 20:16:44.758 * 数据库已保存到磁盘

166:M 22 Jan 2021 20:16:44.758 # Redis 现在准备退出,再见...

2021-01-22 20:16:45.563 UTC [53] LOG: 正在关闭

I, [2021-01-22T20:16:52.806177 #1] INFO -- : HOME=/var/lib/postgresql USER=postgres exec chpst -u postgres:postgres:ssl-cert -U postgres:postgres:ssl-cert /usr/lib/postgresql/13/bin/postmaster -D /etc/postgresql/13/main pid:49 未正常终止,强制终止!

失败

--------------------

Pups::ExecError: cd /var/www/discourse && su discourse -c 'bundle exec rake db:migrate' 失败,返回状态为 #<Process::Status: pid 4032 exit 1>

失败位置:/pups/lib/pups/exec_command.rb:112:in `spawn'

执行失败,参数如下:{"cd"=>"$home", "hook"=>"db_migrate", "cmd"=>["su discourse -c 'bundle exec rake db:migrate'"]}

d627ad17d1f22d839a7dc8099878e6272eb3ea1772539f6628e2a23dd830aca2

** 引导失败 ** 请向上滚动查看之前的错误信息,可能不止一条。

./discourse-doctor 可能有助于诊断问题。

我完全不明白怎么会有两个用户名相同的账户。

我们的网站已经完全无法访问了。现在我该怎么办?

谢谢,
Gunnar

2 个赞

我想你可以通过 ./launcher start app 让站点重新运行起来。

然后查看删除重复项的方法:

5 个赞

我应该提供的更多信息:

  • 这是一个单容器安装。
  • 第一次重建顺利完成,没有任何错误。此错误发生在第一次重建成功完成后,我进行第二次重建时。

谢谢,
Gunnar

1 个赞

磁盘空间是否充足?据我所知,这与所需的 PostgreSQL 更新至版本 13 有关。您是否遵循了此升级方法

cd /var/discourse
git pull
./launcher rebuild app

如果您在论坛中搜索这些错误,将会看到许多过往信息和可能的解决方案。

请尝试此方法。

在论坛中搜索您发布的错误,查看其他人成功使用的各种修复方案。

1 个赞

我通过将 postgres_data_old 重命名为 postgres_data,然后运行 ./launcher start app 启动旧镜像,成功让网站恢复运行。

所以,我现在又回到了起点,但至少网站已经上线了。

我尝试查找重复键,执行了以下命令:

select * from users WHERE username = 'DaveW';

(username = DaveW 是错误消息中显示的问题键,如本线程首帖所示。)

该命令只返回了一行,即一个用户。我漏掉了什么?

谢谢,
Gunnar

1 个赞

您在数据库中确实有两个,可能大小写不同:

1 个赞

你访问过我的网站吗?:wink:

我明白你的意思了。当我在 GUI 中搜索时,确实能看到两个账户。但是,当我以管理员身份点击这两个账户并打开详情页时,它们看起来是同一个用户。我找不到这两个账户之间有任何不同的细节。基本上,无论我点击哪一个,我得到的都是第二个账户(即填入了全名的那个)的数据。

由于该用户从未发过帖,也很久没访问过,我便从 GUI 中删除了该账户。

有趣的是,我仍然有另一个账户,也就是你列表中的第一个,没有全名。但现在,如果我点击该用户,没有任何反应。我可以看到一个对话框试图打开,但随即立即关闭。

直接在数据库中搜索 username = DaveW 现在返回零行。然而,如果我搜索:

select * from users WHERE name = 'DaveW';

(注意是 name,而不是 username),我得到了 1 行结果:

 19732 | DaveW    | 2016-11-15 12:43:02.708166 | 2016-11-15 12:43:02.708166 | DaveW |                    0 |                |               |      | t      | davew          | 2016-11-15 12:43:02.708166 | f     | 2017-06-01 18:09:45.018058 |           1 | f        |                |             |                   |              |                |               |     0 |          0 |            | f         |       |                    |        |                  |                         | f      |               |               |                          |                           | 
(1 row)

请注意,username 字段中显示的是 DaveW(拼写相同)!这个账户也比另一个账户早三年。

我能否通过以下命令将其删除,而不会造成任何不良影响?

DELETE from users WHERE id = 19732;

感谢你的所有帮助!

Gunnar

1 个赞

当然!:grinning:

这应该会删除 19733,但我无法保证不会产生任何不良影响。无论如何,在继续操作之前进行备份是明智之举。

3 个赞

您可能还需要更改其中一个重复用户的用户名。

2 个赞

好的。

一旦我完成更改,是否应该能够从头重新开始升级?也就是说,可以运行两次 rebuild 吗?

谢谢!
Gunnar

4 个赞

这应该能行。除非还有其他重复的用户。

2 个赞

事实证明确实有,至少有一个。

PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(robs) already exists.

有什么方法可以扫描数据库中的重复项吗?不仅仅是用户,还包括任何可能在升级过程中导致此错误的表?

我想在再次尝试之前找到并修复所有这些问题。

此外,最好能将此功能纳入升级流程。也许先运行一次扫描,在任何更改发生之前停止流程。警告用户并提供重复项列表,附带指向此处 meta 页面上修复说明的链接?

2 个赞

一种侵入性较小的方法是在升级前重新索引数据库,这将告诉您需要修复哪些索引。

2 个赞

我不是数据库专家,所以这看起来有点吓人。如果我理解正确的话,这样做之后会出现重复的索引,并且必须手动删除它们吗?

此外,这里有个奇怪的地方。就像你之前在我的网站上发现重复项一样,我现在也在 GUI 中发现了重复用户 RobS。但和之前一样,无论我点击哪一个,最终都会跳转到其中某一个用户的个人资料页面。具体如下:

  • 在 GUI 中列出名为 RobS 的用户。找到两个。发现两者的统计数据不同。
  • 点击用户 #1。看到的是属于用户 #2 的个人资料和统计数据。
  • 点击用户 #2。看到的是属于用户 #2 的个人资料和统计数据。

select * from users WHERE username_lower = 'robs';

返回 1 行:看起来像是用户 #2(日期匹配)。

select * from users WHERE username = 'RobS';

也仅返回 1 行:看起来像是用户 #1(同样,日期匹配)。该用户的 ID 与另一个不同。

根据输出结果判断,它们似乎都有相同的 usernameusername_lower,但每个 SELECT 语句都只返回了 1 行。我的数据库是不是出了严重问题?

重新索引能解决这个问题吗?

2 个赞

我再次尝试重建,发现了一个又一个重复项,用户名为 “drc”。在图形界面中,我找到了这两个用户:

Deborah C
David C

尝试点击任一用户,查看其个人资料“卡片”上的详细信息。你会发现,无论点击哪一个,显示的都是 Deborah C 的详细信息。

我不知道这是怎么发生的,但我现在最好的行动方案是什么?在解决这个问题之前,我已经放弃了升级。

我该如何重新索引?像这样吗?

REINDEX SCHEMA CONCURRENTLY public;

这会告诉我哪些键是重复的吗?

1 个赞

我想知道以下查询会返回什么:

select id, username FROM users WHERE username_lower = 'robs' OR username = 'RobS':

是不是有些愚蠢的原因,比如某个用户名条目中包含空格、不可打印字符或某种 Unicode 字符?

1 个赞

我想可以,但我不确定是否有更好的方法。在我的测试实例上,它只是运行而没有输出任何内容。当我更新生产环境网站时,只有一个重复项需要处理,所以我的经验可能不适用于您的情况。无论如何,在进行数据库操作之前请务必备份——我通常在 DigitalOcean 创建快照,这样万一出现问题,恢复起来会既快速又简单。

1 个赞

我认为我过去就是这样解决类似问题的。重建索引,当它失败时,会提示你哪个是重复项,然后你修复它,再试一次。重复此过程。

2 个赞

谢谢。当它失败时,我该如何找到并删除未完成的新区索引?是否只需在失败的表名后添加"_ccnew"即可?

也就是说,当因重复项导致在"users"上崩溃时,我是否应首先修复重复项,然后执行:

DROP index ‘users_ccnew’;

接着重新运行?是否就这么简单?

谢谢,
Gunnar

1 个赞

啊,是的。我现在遇到了这种情况:我发现了两个有效(且活跃)的用户,它们具有相同的 username 和 username_lower:

  id   | username | (已隐藏) | username_lower |
 42379 | DrC      | (已隐藏) | drc            |
 47695 | DRC      | (已隐藏) | drc            |

看来我需要修改第二个用户的 username 和 username_lower。在 psql 中该如何操作呢?

谢谢!
Gunnar

1 个赞