Autant d'utilisateurs cassés en raison d'une base de données corrompue

Je rencontre un vrai problème avec nombre de mes utilisateurs. Les utilisateurs apparaissent dans le panneau d’administration comme ceci :

Mais lorsque j’essaie de révéler leur adresse e-mail, rien ne s’affiche. De plus, leur profil public renvoie une erreur 404.

À en juger par ce que je vois, tous ces utilisateurs sont presque inactifs (ils sont actifs en termes de validation du compte, mais inactifs en termes d’activité sur le forum). Je pense donc que cela pourrait être dû à une suppression automatique des utilisateurs inactifs défectueuse, remontant à très longtemps.

Autre chose que je remarque :

Si je les désactive, puis que je les réactive, ils sont réparés !

Si un utilisateur est inactif pendant une certaine période (730 jours par défaut), il est automatiquement désactivé. Le paramètre se trouve dans votre tableau de bord sous Paramètres/Utilisateurs, en faisant défiler la page presque jusqu’en bas. C’est là que vous le verrez. Cependant, il n’est pas nécessaire de modifier quoi que ce soit uniquement pour le plaisir de changer. Si ces utilisateurs n’ont pas connecté leur compte depuis 2 ans, il n’a aucun sens de les réactiver sauf s’ils réapparaissent. :wink:

Non. Mon problème n’est pas là. Le tableau de bord indique que les utilisateurs sont activés.

Cela semble similaire à le problème que je rencontre. Pourriez-vous vérifier si les noms concernés comportent des doublons ou des « correspondances très proches » dans votre base de données ? Par exemple user.user et useruser.

Oui, les utilisateurs concernés font partie de ceux dont les noms d’utilisateur sont très populaires. Ainsi, Discourse suggère un nom d’utilisateur proche. J’inscris les utilisateurs via l’API. Je récupère donc un nom d’utilisateur de la part de l’utilisateur, puis je le vérifie auprès de l’API de Discourse. S’il est déjà pris, j’utilise automatiquement la suggestion de Discourse.

D’ailleurs, avec l’aide de @RGJ, nous avons identifié le problème comme étant lié à ces deux conditions :

Pour compléter, le problème que rencontre @hosna est clairement un problème au niveau de la base de données. Il semble y avoir une certaine corruption dans la table des utilisateurs. Copier le contenu dans une nouvelle table résout ces problèmes.

Cela dit, j’ai remarqué deux occurrences du problème de @bartv dans la base de données de @hosna (ceux étaient les deux doublons avant le 22 septembre et ils avaient tous les deux un point dans leur nom d’utilisateur), mais je ne suis pas sûr que ces deux problèmes soient liés. Ils présentent simplement les mêmes symptômes.

Cela ressemble à un index de base de données corrompu. REINDEX TABLE users devrait résoudre le problème.

Qu’en est-il des noms d’utilisateur en double ? J’ai de nombreux noms d’utilisateur identiques utilisés pour deux utilisateurs distincts.

Le problème est reconnu ici :

C’est probablement un effet secondaire d’un index corrompu. Vous devrez peut-être le nettoyer manuellement avant que la réindexation ne fonctionne.

Pouvez-vous expliquer comment un index corrompu peut se produire et comment l’éviter à l’avenir ?

Panne matérielle, bug dans Postgres… difficile à dire. Ça arrive.

Sauf que c’est impossible car l’index est corrompu.
Voici la solution :

# créer une table temporaire sans contraintes et copier le contenu dedans
create table users_test (like users);
insert into users_test select * from users;

# supprimer les noms d'utilisateur en double sensibles à la casse, les doublons sont après le 22 septembre
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' ;

# supprimer les noms d'utilisateur en double insensibles à la casse, les doublons sont après le 22 septembre
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' ;

# deux problèmes de plus à résoudre, supprimez-les individuellement
delete from users_test where id in (184534,130826);

# créer une nouvelle table avec contraintes et copier les utilisateurs
create table users_clean (like users including indexes);
insert into users_clean select * from users_test;

puis renommez users en users_old et users_clean en users.

Je voudrais intervenir ici pour dire que cela pourrait endommager votre base de données encore plus que les utilisateurs cassés !

Nous sommes maintenant coincés à mi-chemin entre les mises à jour, car de nombreuses contraintes reposent toujours sur users_old depuis que nous avons renommé la table. Ce problème n’a été signalé que quelques jours après l’application de ce correctif apparemment incomplet. De plus, like users including indexes n’est pas suffisant (il ignorera par exemple la séquence id).

Vous avez tout à fait raison, je me souviens en effet avoir dû recréer les contraintes après avoir renommé les tables. Je m’excuse pour cette omission importante.

D’après mes notes :

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);

Et de nos jours aussi :

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

Et comme avertissement important : n’utilisez cela que si vous savez absolument ce que vous faites !

Cela correspond en effet à ce que nous avons constaté après avoir interrogé pg_catalog pour les contraintes affectant users_old.

De plus, je me rappelle que including defaults était au minimum nécessaire pour ne pas casser l’inscription.

Merci pour la rectification !