Liens vers des téléchargements brisés dans les sujets entraînent des erreurs 500 avec 2.5.0

Je gère un site Discourse et je tiens d’abord à dire à quel point j’adore ce logiciel. Merci à toute l’équipe pour ce travail formidable, c’est un outil génial.

Après une mise à niveau vers la version 2.5.0, j’ai rencontré de sérieux problèmes. Voici un récapitulatif et la solution de contournement que j’ai mise en place. Peut-être cela permettra-t-il d’obtenir une correction bien meilleure dans les futures versions.

Certains des sujets présents dans notre base de données contiennent des pièces jointes corrompues. Nous avons utilisé la fonctionnalité « Téléchargements S3 » et avons supprimé le bucket par erreur. Oui, c’est une chose très stupide à faire, mais bon, nous l’avons fait ! Le résultat a été la perte de toutes les images des sujets.

À part le fait que nous avions perdu de nombreuses images, tout allait bien : Discourse affichait des liens brisés vers des images inexistantes, mais le reste fonctionnait correctement.

Mais lorsque nous avons voulu passer à la version 2.5.0, tout a déraillé : tous les utilisateurs connectés ont reçu des erreurs 500, tandis que les visiteurs anonymes pouvaient toujours voir le site.

Après investigation, j’ai réalisé que Discourse plantait à cause d’erreurs « Fichier introuvable ». Il semblait essayer de les télécharger. J’ai dû forcer la méthode local? à true dans /var/www/discourse/app/models/upload.rb, et cela a résolu le problème, mais je suis un peu inquiet pour les prochaines mises à jour…

C’est clairement quelque chose de nouveau, car les mises à jour précédentes ne posaient aucun problème.

Au fait, existe-t-il une méthode pour supprimer tous les liens d’images morts présents dans nos sujets ?

Merci.

Nous observons le comportement inverse : l’utilisateur connecté fonctionne bien, mais les utilisateurs non connectés ne peuvent pas se connecter et reçoivent une erreur 500.

Pourriez-vous partager une trace d’appel complète d’une telle erreur ?
Vérifiez votre page /logs.

Cela ressemble beaucoup à un plugin incompatible. Quels plugins non officiels utilisez-vous ? Avez-vous essayé de reconstruire sans eux ?

Bien sûr, dans mon fichier log/production.log, j’ai rencontré l’exception suivante (lorsque Discourse tentait d’accéder au bucket S3 vide (que j’ai recréé, espérant que cela résoudrait le problème)).

Début de la requête GET “/” depuis 86.246.127.170 à 14:29:06 le 2020-05-16 +0000
Traitement par ListController#latest en HTML
Création de la portée :open. Écrasement de la méthode existante Poll.open.
Terminé avec une erreur 500 Internal Server Error en 3638 ms (ActiveRecord : 0,0 ms | Allocations : 135090)
NoMethodError (la méthode path n’existe pas pour nil:NilClass)
/var/www/discourse/lib/file_store/base_store.rb:150:in `cache_file’

J’espère que cela t’aidera.

Merci, c’est peut-être cela. J’ai effectivement deux plugins installés : Discourse Adsense et discourse-chat-integration. Je vais essayer de reconstruire sans eux.

Je peux confirmer que cela n’est pas causé par un plugin : j’ai reproduit le même bug avec une installation fraîche + une restauration de ma dernière sauvegarde et aucun plugin installé sauf docker_manager.

La première trace d’erreur que j’obtiens est :

Terminé avec une erreur interne du serveur 500 en 4169 ms (ActiveRecord : 0,0 ms | Allocations : 72058)
NoMethodError (méthode path non définie pour nil:NilClass)
/var/www/discourse/lib/file_store/base_store.rb:150:in `cache_file’

Je l’ai corrigé de cette manière :

def cache_file(file, filename)
path = get_cache_path_for(filename)
dir = File.dirname(path)
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)

  if file.nil?
    return
  end

  FileUtils.cp(file.path, path)

Ce qui a entraîné une deuxième erreur (celle que j’ai mentionnée dans mon message initial) :

Démarrage de la requête GET “/” pour 86.246.127.170 le 2020-05-18 07:37:40 +0000
Traitement par CategoriesController#index en tant que HTML
Terminé avec une erreur interne du serveur 500 en 4342 ms (ActiveRecord : 0,0 ms | Allocations : 60478)
NoMethodError (méthode path non définie pour nil:NilClass)
/var/www/discourse/app/models/upload.rb:193:in `fix_dimensions!’

Que j’ai corrigée en forçant local? à true :

def local?
return true
!(url =~ /^(https?:)?///)
end

Avez-vous déplacé vos fichiers vers ou depuis S3 à un moment donné ?

Oui, je l’ai fait. Mais ensuite, le bucket a été supprimé. Et je suis revenu au stockage local (avec des liens d’images brisés dans les sujets précédents, bien sûr).

Je pense que la meilleure solution ici est de supprimer définitivement toutes les lignes d’upload erronées de votre base de données.

Si vous n’avez aucun upload, ne le gardez pas.

Oui, je suis d’accord, mais j’ai peur d’exécuter manuellement une telle commande de suppression sur la base de données. Auriez-vous des suggestions pour le faire « correctement » ? Ou devrais-je vraiment le faire « à la main » ?

Par ailleurs, j’ai le sentiment que ce changement de comportement de Discourse est quelque peu inquiétant. Cela signifie, autant que je puisse en juger, que si un lien vers une image morte apparaît quelque part à un moment donné, l’application va planter.

Ce n’était pas le cas auparavant. Je suggère de rendre le système plus robuste dans de telles situations.

Très proche de ce que nous avons :

C’est « résolu » en relançant la configuration de l’assistant !

Oui, cela ressemble au même problème. @sukria, si vous mettez à jour vers la dernière version « tests-passed », j’ai ajouté une correction qui rend le système plus robuste face aux téléchargements corrompus (bien que vous deviez toujours essayer de nettoyer les références aux téléchargements corrompus).

Je suis également intéressé par un moyen simple de nettoyer ces liens brisés aussi :wink:

Merci @david, je confirme qu’une nouvelle reconstruction par rapport à tests-passed a fonctionné sans problème. Merci !
Une suggestion sur une méthode appropriée et simple pour se débarrasser de ces liens morts dans les sujets ?