Не удается загрузить аватары при включенном хранилище S3 (файл существует, но ошибка сохраняется)

Всем привет,

У меня возникла странная проблема с Discourse и хранилищем S3.

При загрузке аватаров появляется ошибка, как показано ниже, хотя файл действительно существует в бакете S3 и доступен по корректному s3_cdn_url.

Загрузка постов и вложений работает безупречно. Неудачей заканчиваются только загрузки аватаров пользователей.


:fire: Сообщение об ошибке из gig.ovh/logs


Сообщение (2 записи)

Не удалось найти файл в хранилище по адресу: //gig.s3.ru-1.storage.selcloud.ru/original/1X/fd42dfa3362b66090450f2ae40f0917193fcd355.jpeg

Трассировка стека

/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active\_support/broadcast\_logger.rb:134\:in `block in error'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active_support/broadcast_logger.rb:231:in `block in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active\_support/broadcast\_logger.rb:231\:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active_support/broadcast_logger.rb:231:in `dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active\_support/broadcast\_logger.rb:134\:in `error'
/var/www/discourse/app/models/optimized_image.rb:91:in `block in create\_for'
/var/www/discourse/app/models/optimized\_image.rb:19\:in `block (2 levels) in lock'
/var/www/discourse/lib/distributed_mutex.rb:53:in `block in synchronize'
/var/www/discourse/lib/distributed\_mutex.rb:49\:in `synchronize'
/var/www/discourse/lib/distributed_mutex.rb:49:in `synchronize'
/var/www/discourse/lib/distributed\_mutex.rb:34\:in `synchronize'
/var/www/discourse/app/models/optimized_image.rb:19:in `block in lock'
/var/www/discourse/lib/distributed\_mutex.rb:53\:in `block in synchronize'
/var/www/discourse/lib/distributed_mutex.rb:49:in `synchronize'
/var/www/discourse/lib/distributed\_mutex.rb:49\:in `synchronize'
/var/www/discourse/lib/distributed_mutex.rb:34:in `synchronize'
/var/www/discourse/app/models/optimized\_image.rb:18\:in `lock'
/var/www/discourse/app/models/optimized_image.rb:83:in `create\_for'
/var/www/discourse/app/models/upload.rb:151\:in `get_optimized_image'
/var/www/discourse/app/controllers/user_avatars_controller.rb:219:in `get\_optimized\_image'
/var/www/discourse/app/controllers/user\_avatars\_controller.rb:137\:in `show_in_site'
/var/www/discourse/app/controllers/user_avatars_controller.rb:90:in `block (2 levels) in show'
/var/www/discourse/lib/hijack.rb:68\:in `instance_eval'
/var/www/discourse/lib/hijack.rb:68:in `block (2 levels) in hijack'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/i18n-1.14.7/lib/i18n.rb:353\:in `with_locale'
/var/www/discourse/lib/hijack.rb:68:in `block in hijack'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:911\:in `callback_on_resolution'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:797:in `call\_callback'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:803\:in `call_callbacks'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:692:in `resolve\_with'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1325\:in `resolve'
/var/www/discourse/lib/scheduler/defer.rb:125:in `block in do\_work'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails\_multisite-6.1.0/lib/rails\_multisite/connection\_management/null\_instance.rb:49\:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management.rb:21:in `with\_connection'
/var/www/discourse/lib/scheduler/defer.rb:119\:in `do_work'
/var/www/discourse/lib/scheduler/defer.rb:105:in `block (2 levels) in start\_thread'

Это S3-ссылка на контейнер:

//gig.s3.ru-1.storage.selcloud.ru/original/1X/fd42dfa3362b66090450f2ae40f0917193fcd355.jpeg

Изображение доступно по адресу:

https://s3.gig.ovh/original/1X/fd42dfa3362b66090450f2ae40f0917193fcd355.jpeg

:white_check_mark: Дополнительная информация

  • Версия Discourse: (последняя стабильная)
  • Используется внешнее хранилище, совместимое с S3 (enable_s3_uploads = true)
  • s3_cdn_url настроен корректно и используется
  • CDN-ссылка успешно возвращает файл
  • Файл подтверждено присутствует в ожидаемом месте S3
  • Другие загрузки (изображения, вложения и т. д.) работают нормально
  • Ошибка возникает только с аватарами пользователей

:red_question_mark: Вопрос

Что может вызывать сбой Discourse при попытке получить файл для обработки аватара, если файл существует и доступен по корректному CDN-адресу?

Возможно, есть какая-то специфика обработки аватаров (например, get_optimized_image), которая настроена неверно или кэшируется неправильно?

Буду признателен за любые предложения или подсказки!

Спасибо :folded_hands:

Привет! Вы уже решили эту проблему?

У меня возникает точно такая же ошибка с Discourse + S3 (только для аватаров):
Could not find file in the store located at url: //<bucket>.s3.dualstack.<region>.amazonaws.com/original/1X/<hash>.jpeg

Несколько деталей о моей конфигурации, на случай если она совпадает с вашей:

  • enable_s3_uploads = true, объекты хранятся по путям original/* и optimized/* (без префикса uploads/default)

  • Доступ осуществляется через CloudFront (OAC), сам бакет приватный

  • Объект существует по указанному ключу; URL CDN работает

  • Ошибка возникает только при обработке аватаров

  • (Возможная сложность) загрузки зашифрованы с использованием SSE-KMS

Если вы нашли корневую причину или решение (изменение политики, права доступа KMS, согласование путей в бакете и т. д.), пожалуйста, поделитесь, что помогло. Спасибо!