データベース破損により多数のユーザーが破損

多くのユーザーに深刻な問題が発生しています。管理パネルでは、ユーザーは次のように表示されます。

しかし、メールアドレスを表示しようとすると何も表示されません。また、公開プロフィールには 404 エラーが表示されます。

私の観察によると、これらのユーザーはほぼ inactive(アクティベーションはされているが、フォーラムでの活動は inactive)です。おそらく、非常に昔に設定された自動 inactive ユーザー削除処理に不具合があったことが原因ではないかと考えています。

もう一つ気づいたことがあります。

無効化してから再度有効化すると、修正されます!

ユーザーが一定期間(デフォルトでは 730 日)非アクティブな場合、自動的に無効化されます。この設定は、ダッシュボードの「設定/ユーザー」から、ほぼ一番下までスクロールすると確認できます。ただし、変更の必要性がない限り、あえて変更する必要はありません。2 年間ログインしていないユーザーを、再び現れる兆候がない限り再有効化する意味はありません。:wink:

いいえ、私の問題はそれではありません。ダッシュボードにはユーザーがアクティブ化されたと表示されています。

私が抱えている問題と似ているようです。影響を受けている名前に、データベース内に重複や「非常に近い一致」がないか確認していただけますか?例えば user.useruseruser のようなケースです。

はい、影響を受けたユーザーは非常に人気のあるユーザー名を持つ方々です。そのため、Discourse が類似したユーザー名を提案します。私は API を使ってユーザーを登録しており、ユーザーからユーザー名を取得します。その後、Discourse の API でそのユーザー名が既に使用されているか確認し、もし既に使われていれば、Discourse が提案するものを自動的に採用します。

ちなみに、@RGJ の助けを借りて、問題は以下の 2 つの条件に特定されました:

さらに付け加えると、@hosna さんが直面している問題は、明らかにデータベースレベルの課題です。users テーブルに何らかの破損があるようです。内容を新しいテーブルにコピーすることで、これらの問題は解決します。

とはいえ、@hosna さんのデータベースでは @bartv さんの問題が 2 回発生しているのを確認しました(9 月 22 日以前の 2 つの重複で、どちらもユーザー名にドットが含まれていました)。ただし、これら 2 つの問題が関連しているかどうかは確信が持てません。単に症状が同じというだけです。

破損したデータベースインデックスのようです。REINDEX TABLE users で問題が解決するはずです。

重複したユーザー名についてはどうですか?同じユーザー名が2人の異なるユーザーによって使用されているケースが多数あります。

この問題はここで認識されています:

おそらく、破損したインデックスによる副作用です。再インデックス化が機能する前に、手動でそれを整理する必要があるかもしれません。

破損したインデックスがどのように発生するのか、そして将来それを防ぐためにどうすればよいのか、説明していただけますか?

ハードウェア障害、Postgres のバグなど、原因は特定しにくいです。よくあることです。

ただし、インデックスが破損しているため、それは不可能です。
これで解決します:

# 制約のない一時テーブルを作成し、その中に内容をコピーします
create table users_test (like users);
insert into users_test select * from users;

# 大文字小文字を区別した重複ユーザー名を削除します(重複は9月22日以降)
delete from users_test where username in (
  select username 
  from users_test 
  group by username 
  having count(username)>1
) and created_at>'2019-09-22' ;

# 大文字小文字を区別しない重複ユーザー名を削除します(重複は9月22日以降)
delete from users_test where lower(username) in (
  select lower(username) 
  from users_test 
  group by lower(username) 
  having count(lower(username))>1
) and created_at > '2019-09-22' ;

# 残りの2つの問題も個別に削除します
delete from users_test where id in (184534,130826);

# 制約付きの新しいテーブルを作成し、ユーザーをコピーします
create table users_clean (like users including indexes);
insert into users_clean select * from users_test;

その後、usersusers_oldに、users_cleanusersに名前を変更します。

ここで一言付け加えさせてください。これは、壊れたユーザーデータ以上にデータベースを破損させる可能性があります

テーブルをリネームしたため、多くの制約がまだ users_old に依存しており、私たちはアップグレードの途中で立ち往生してしまいました。この不完全な修正を適用してから数日後にのみこの問題が表面化しました。また、like users including indexes だけでは不十分です(例えば、id シーケンスが無視されてしまいます)。

おっしゃる通りです。テーブル名を変更した後、制約を再作成する必要があったことを確かに覚えております。
この重要な見落としについてお詫び申し上げます。

私のメモによると:

alter table poll_votes drop constraint fk_rails_b64de9b025;
alter table poll_votes add constraint fk_rails_b64de9b025 FOREIGN KEY (user_id) REFERENCES users(id);

alter table user_security_keys drop constraint fk_rails_90999b0454;
alter table user_security_keys add  constraint fk_rails_90999b0454 FOREIGN KEY (user_id) REFERENCES users(id);

そして現在では、以下も必要です:

alter table bookmarks drop constraint fk_rails_c1ff6fa4ac;
alter table bookmarks add  constraint fk_rails_c1ff6fa4ac FOREIGN KEY (user_id) REFERENCES users(id);

重要な免責事項として:これを適用するのは、自分が何をしているかを完全に理解している場合に限ってください

これは、users_old に影響を与える制約を pg_catalog で照会した後に私たちが発見した内容と確かに一致しているようです。

また、登録機能を壊さないためには、少なくとも including defaults を含める必要があったと記憶しています。

修正ありがとうございます!