Tantos usuários corrompidos devido a banco de dados corrompido

Tenho um problema real com muitos dos meus usuários. Os usuários podem ser vistos no painel de administração assim:

Mas quando tento revelar o endereço de e-mail deles, nada é exibido para mim. Além disso, o perfil público deles retorna um erro 404.

Pelo que vejo, todos esses usuários estão quase inativos (eles estão ativos no que diz respeito à ativação da conta, mas inativos em termos de atividade no fórum). Então, acho que isso pode ter sido causado por uma remoção automática de usuários inativos defeituosa há muito tempo.

Outra coisa que eu percebo:

Se eu desativar e, em seguida, ativá-los, eles são corrigidos!

Se um usuário ficar inativo por um determinado período (730 dias por padrão), ele será automaticamente desativado. A configuração está no seu painel, em Configurações/Usuários, quase no final da página. É lá que você verá essa opção. No entanto, não é necessário fazer alterações apenas pelo sake de mudar. Se esses usuários não fizeram login há 2 anos, não faz sentido reativá-los, a menos que voltem a aparecer. :wink:

Não. Meu problema não é esse. O painel diz que os usuários estão ativados.

Parece semelhante ao problema que estou enfrentando. Você poderia verificar se os nomes afetados têm duplicatas ou ‘correspondências muito próximas’ no seu banco de dados? Por exemplo, user.user e useruser.

Sim, os usuários afetados estão entre aqueles com nomes de usuário muito populares. Assim, o Discourse sugere um nome de usuário próximo. Eu cadastro usuários via API. Então, recebo um nome de usuário do usuário, verifico-o contra a API do Discourse e, se já estiver em uso, uso automaticamente qualquer sugestão que o Discourse oferecer.

Aliás, com a ajuda do @RGJ, identificamos o problema nestas duas condições:

Para complementar, o problema que @hosna está enfrentando é claramente um problema no nível do banco de dados. Parece haver alguma corrupção na tabela de usuários. Copiar o conteúdo para uma nova tabela resolve esses problemas.

Dito isso, observei duas ocorrências do problema de @bartv no banco de dados de @hosna (esses foram os dois duplicados antes de 22 de setembro e ambos tinham um ponto no nome de usuário), mas não tenho certeza se esses dois problemas estão relacionados. Eles apenas apresentam os mesmos sintomas.

Parece um índice de banco de dados corrompido. REINDEX TABLE users deve resolver o problema.

E quanto aos nomes de usuário duplicados? Tenho muitos nomes de usuário iguais sendo usados para dois usuários distintos.

O problema foi reconhecido aqui:

Isso provavelmente é um efeito colateral de um índice corrompido. Você pode precisar limpá-lo manualmente antes que a reindexação funcione.

Você pode explicar como um índice corrompido pode ocorrer para evitá-lo no futuro?

Falha de hardware, bug no Postgres… Difícil dizer. Acontece.

Exceto que isso é impossível, pois o índice está corrompido.
Isso resolve o problema:

# cria uma tabela temporária sem restrições e copia o conteúdo para ela
create table users_test (like users);
insert into users_test select * from users;

# remove nomes de usuário duplicados (sensíveis a maiúsculas/minúsculas), as duplicatas são após 22 de setembro
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' ;

# remove nomes de usuário duplicados (insensíveis a maiúsculas/minúsculas), as duplicatas são após 22 de setembro
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' ;

# dois problemas restantes, exclua-os individualmente
delete from users_test where id in (184534,130826);

# cria uma nova tabela com restrições e copia os usuários
create table users_clean (like users including indexes);
insert into users_clean select * from users_test;

Em seguida, renomeie users para users_old e users_clean para users.

Gostaria de intervir aqui para dizer que isso pode quebrar ainda mais seu banco de dados do que os usuários com problemas!

Agora estamos presos no meio do caminho entre as atualizações, pois muitas restrições ainda dependem de users_old desde que renomeamos a tabela, e isso só foi mostrado como um problema alguns dias após aplicar essa correção aparentemente incompleta. Além disso, like users including indexes não é suficiente (por exemplo, ele ignorará a sequência id).

Você tem toda a razão, de fato lembro de ter que recriar as restrições após renomear as tabelas.
Peço desculpas por essa omissão importante.

De minhas anotações:

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

E atualmente também:

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

E como um aviso importante: use isso apenas quando tiver absoluta certeza do que está fazendo!

Isso realmente parece corresponder ao que encontramos ao consultar pg_catalog para restrições que afetam users_old.

Além disso, lembro que including defaults era no mínimo necessário para não quebrar o registro.

Obrigado pela correção!