Пользовательские аватары «исчезли» после обновления до 3.3.0beta1

Здравствуйте,

Недавно мы обновили наши тестовые форумы до версии 3.3.0beta1. Тестовый форум представляет собой несколько устаревшую (с точки зрения контента) копию наших основных форумов. Мы используем его для тестирования обновлений и новых функций. Он использует то же подключение к Amazon S3 для загрузки файлов, что и основные форумы.

После обновления операционной системы хоста до последней версии Ubuntu 24.04 LTS и обновления форумов до версии 3.3.0beta1 все пользовательские аватары исчезли, и вместо них отображается белый/серый силуэт головы.

При просмотре журналов я обнаружил сообщения следующего вида:

Could not find file in the store located at url: //ourbucket.s3.dualstack.eu-central-1.amazonaws.com/original/3X/6/9/69ca9110f27d91561axyz52a9cd9485a970fe9.jpeg

При этом изображение фактически существует по указанному URL и открывается без проблем. Я попробовал загрузить файл с сервера с помощью wget, чтобы проверить, нет ли проблем с DNS или других препятствий, которые могли бы помешать локальному прокси аватаров получить его, но и это не помогло.

Есть ли у вас какие-либо идеи, что может происходить?

Похоже, это происходит не только на тестовых форумах, но и на рабочих форумах: аватары исчезают по частям, и в логах наблюдаются те же ошибки.

Интересно, не очищает ли тестовый форум файлы, которые он не ожидает увидеть в бакете S3, но вы говорите, что файлы находятся в бакете, так что дело не в этом. Возможно, стоит восстановить базу данных для тестирования и посмотреть, что находится в модели загрузок.

Дело в том, что сообщение об ошибке в логе указывает на невозможность загрузки определённого изображения, хотя это самое изображение фактически доступно. Похоже, что-то мешает форуму или прокси аватаров загрузить это изображение.

Я только что загрузил новое изображение аватара на тестовый сервер (версия 3.3.0beta1). Загрузка прошла успешно, изображение отобразилось в превью, но затем снова не загрузилось.

/var/www/discourse/app/models/optimized_image.rb:81: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:73:in `create_for' 
/var/www/discourse/app/models/upload.rb:130:in `get_optimized_image' 
/var/www/discourse/app/controllers/user_avatars_controller.rb:218:in `get_optimized_image' 
/var/www/discourse/app/controllers/user_avatars_controller.rb:136:in `show_in_site' 
/var/www/discourse/app/controllers/user_avatars_controller.rb:89:in `block (2 levels) in show' 
/var/www/discourse/lib/hijack.rb:64:in `instance_eval' 
/var/www/discourse/lib/hijack.rb:64:in `block in hijack' 
concurrent-ruby-1.2.3/lib/concurrent-ruby/concurrent/promises.rb:911:in `callback_on_resolution' 
concurrent-ruby-1.2.3/lib/concurrent-ruby/concurrent/promises.rb:797:in `call_callback' 
concurrent-ruby-1.2.3/lib/concurrent-ruby/concurrent/promises.rb:803:in `call_callbacks' 
concurrent-ruby-1.2.3/lib/concurrent-ruby/concurrent/promises.rb:692:in `resolve_with' 
concurrent-ruby-1.2.3/lib/concurrent-ruby/concurrent/promises.rb:1325:in `resolve' 
/var/www/discourse/lib/scheduler/defer.rb:115:in `block in do_work' 
rails_multisite-5.0.1/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
rails_multisite-5.0.1/lib/rails_multisite/connection_management.rb:21:in `with_connection'
/var/www/discourse/lib/scheduler/defer.rb:109:in `do_work' 
/var/www/discourse/lib/scheduler/defer.rb:97:in `block (2 levels) in start_thread' 

Это данные из лога.

Соответствующее сообщение лога:

Could not find file in the store located at url: //ourbucket.s3.dualstack.eu-central-1.amazonaws.com/original/3X/0/2/02832e36e27bbad791fda46e2290df31e5ee2dda.jpeg

(Я изменил URL, чтобы он не работал, хотя оригинальный URL корректен)

Меня больше всего беспокоит строка 'block in hijack'.

На боевом сервере мы работаем за Cloudflare. Тестовый сервер настроен «только DNS», поэтому, очевидно, не фильтруется через Cloudflare. В последнее время у нас были проблемы с ботами на основном сайте, и мы довольно активно настраивали фильтры Cloudflare.

Но тогда почему загрузка по адресу amazonaws.com может стать проблемой? К тому же тестовый сайт вообще не проходит через Cloudflare.

Честно говоря, я немного запутался.

Я действительно застрял на этом вопросе. Похоже, проблема затрагивает как живые, так и тестовые форумы — на живом форуме всё ещё установлена более старая версия, и проблема, кажется, возникла не из-за обновления, а появилась несколько дней назад без каких-либо заметных изменений.

Суть в следующем: Discourse корректно загружает новые пользовательские аватары в S3, устанавливает для них ACL (насколько я могу судить, верно), и файлы также доступны публично по URL, который Discourse пытается использовать для их подгрузки в прокси аватаров. Тем не менее, это не удаётся (см. стек вызовов выше).

Есть ли у кого-то с хорошим пониманием того, как работает прокси аватаров, какие-то идеи или можно ли что-то извлечь из этого стека вызовов?

Я сделал wget для URL изображения с серверов, и всё работает нормально — значит, там нет ничего, что могло бы блокировать доступ к этому URL.

А вы можете получить их через браузер?

Ах да, извините, если это было непонятно. Я могу получить к ним доступ через браузер (поэтому я предположил, что они общедоступны), а также с сервера (чтобы исключить проблемы сервера с их получением). Дело действительно только в том, что Discourse по какой-то причине не получает их (см. трассировку стека выше).

Вы нашли решение своей проблемы? У нас возникла точно такая же проблема в версии 3.2.1. В бакете все публичные доступы заблокированы, однако он всё ещё работал через подписанные URL-адреса. Сейчас у меня возникает точно такая же ошибка:

Не удалось найти файл в хранилище по адресу: