升级期间重复键值违反表的唯一约束

大家好,我在维护的一个论坛上遇到了一个奇怪的问题。

在升级过程中,无论是在 admin/upgrade 页面还是终端中,操作都失败了,并出现以下错误:

--------------------------------------------------------------------------------
1 次迁移失败!

默认迁移失败
#<ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_screened_ip_addresses_on_ip_address"
DETAIL:  Key (ip_address)=(10.0.0.0/8) already exists.

幸运的是,我没有搞坏论坛,通过运行 ./launcher restart app 命令(./launcher destroy app / ./launcher start app 曾在我遇到重启后空白页时救过我一回),所以完全没有紧急情况,这也是我想寻求指导的原因。

我决定检查数据库,发现有一些指向 IP 10.0.0.0/8 的引用,看起来像是某些日志,但在 screened_ip_addresses 表中,我没有发现任何重复项。

--
-- TOC 条目 6829 (class 0 OID 382198)
-- 依赖项:657
-- screened_ip_addresses 的数据;类型:TABLE DATA;模式:public;所有者:-
--

COPY public.screened_ip_addresses (id, ip_address, action_type, match_count, last_match_at, created_at, updated_at) FROM stdin;
236	10.0.0.0/8	2	0	\N	2020-05-24 19:44:41.587257	2020-05-24 19:44:41.587257
237	192.168.0.0/16	2	0	\N	2020-05-24 19:44:47.150337	2020-05-24 19:44:47.150337
239	172.16.0.0/12	2	0	\N	2020-05-24 19:44:57.347656	2020-05-24 19:44:57.347656
240	fc00::/7	2	0	\N	2020-05-24 19:45:02.270948	2020-05-24 19:45:02.270948
261	154.71.107.147	1	0	\N	2020-06-05 13:15:17.718236	2020-06-07 00:27:57.204765
257	154.126.107.81	1	0	\N	2020-06-02 09:51:31.191431	2020-06-07 00:27:58.538628
259	197.1.186.242	1	0	\N	2020-06-05 08:39:52.218198	2020-06-07 00:27:58.985867
258	89.158.72.7	1	0	\N	2020-06-02 20:44:41.584317	2020-06-07 00:27:59.542337
260	196.179.229.13	1	0	\N	2020-06-05 08:39:52.227515	2020-06-07 00:28:00.288445
238	127.0.0.0/8	2	0	\N	2020-05-24 19:44:52.369958	2020-05-24 19:44:52.369958

论坛管理员告诉我,他在 /admin/logs/screened_ip_addresses 页面清理了一些 IP 并添加了一些新 IP。但我怀疑他并没有动过这个 IP。奇怪的是,系统显示该 IP 是在 14 天前添加的(那是上次升级的时间,很可能是 PostgreSQL 升级),尽管该论坛创建于 2015 年。而在其他论坛上,检查的是创建日期。

所以我想,这张表可能有点混乱,但看起来又不太像。

我不太想冒险尝试,尤其是因为我不擅长 SQL。因此,我想请教一下正确的操作流程,以确保能够安全升级::raising_hands:

我是否应该清理页面 /admin/logs/screened_ip_addresses,尝试清除该表或其他表的条目?

听起来索引已损坏。您可以查看其他关于索引损坏的主题。\n\n首先,您可以尝试重建索引。另外请注意,许多搜索无法找到重复条目,因为它们假设索引正常工作。

谢谢,可以确认一下,大概是这样的操作吗?

cd /var/discourse
./launcher enter app
su postgres
psql
\connect discourse
REINDEX SCHEMA CONCURRENTLY public;

如果因为系统认为索引正常而此方法无效,考虑到该表的大小,这个方案可行吗?

TRUNCATE public.screened_ip_addresses

我先执行重建索引,然后再手动添加这些 IP 吗?

我现在用的是手机,所以你得自己查文档(RTFM),但我建议只重建 public.screened_ip_addresses。我想当你这样做时,会看到关于冲突的错误提示。

谢谢,我运行了命令,没有提到错误。我几小时后再尝试一次重建,看看结果。

编辑:好的,重新索引没有起到任何作用。

1 次迁移失败!

默认迁移失败
#<ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: 重复键值违反了唯一约束 "index_screened_ip_addresses_on_ip_address"
DETAIL: 键 (ip_address)=(10.0.0.0/8) 已存在。
>

我重启了应用,清理了 /admin/logs/screened_ip_addresses 中的所有 IP,并成功升级

IP 地址已恢复,无需手动添加。

也许我过于谨慎了,但这不是我的论坛,我不想把事情搞砸。感谢 @pfaffman 的帮助!

我想下次如果再次发生这种情况,我会知道如何解决。

这是该主题的最后一次更新,上次我是通过 admin/upgrade 页面进行升级的。这次我想通过终端重新构建以确保万无一失。没有迁移问题,一切顺利。

我可以确认该问题已解决::raised_hands: