Обновление до 3.0.2: NameError: неопределенный метод `call' для класса `Redis::Client' (с "исправлением")

Только что попробовал обновиться с версии 3.0.1 до 3.0.2 и получил эту ошибку на этапе rake db:migrate:

rake aborted!
NameError: undefined method `call' for class `Redis::Client'
Did you mean?  caller
/var/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/mini_profiler/profiling_methods.rb:83:in `alias_method'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/mini_profiler/profiling_methods.rb:83:in `profile_method'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/mini_profiler/profiling_methods.rb:65:in `counter_method'
/var/discourse/config/initializers/006-mini_profiler.rb:90:in `<main>'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/engine.rb:667:in `load'

Если коротко: я обнаружил, что фиксация версии Redis на 4.8.0 вместо указания неопределённой версии в файле Gemfile решает проблему. То есть для файла Gemfile нужно сделать следующее:

-gem "redis"
+gem "redis", "4.8.0"

Мне не очень комфортно копаться в этом, но, как мне кажется, это непреднамеренный побочный эффект обновления Redis в другом месте после моего последнего обновления (до 3.0.1), и повторная установка Discourse 3.0.1 сейчас приведёт к той же проблеме.

Надеюсь, это кому-то поможет. И, пожалуйста, дайте знать, не остаётся ли моя система в уязвимом состоянии после этого :slight_smile:

Мы устанавливаем версии гемов в файле Gemfile.lock, и он уже настроен на эту же версию

Действительно странно, ведь я раньше никогда не слышал ни о Gemfile, ни о Gemfile.lock. Но поскольку мне предстояло повторить установку на 20 других серверах (вздох), оказалось, что всё началось с другой проблемы при установке, где жалобы заканчивались рекомендацией попробовать удалить Gemfile.lock:

Bundler found conflicting requirements for the Ruby version:
  In Gemfile:
    actionmailer (= 7.0.4.3) was resolved to 7.0.4.3, which depends on
      Ruby (>= 2.7.0)

    sassc-rails was resolved to 2.1.2, which depends on
      sprockets-rails was resolved to 3.4.2, which depends on
        Ruby (>= 2.5)

    json was resolved to 2.6.3, which depends on
      Ruby (>= 2.3)
:
:
:
    json_schemer was resolved to 0.2.23, which depends on
      ecma-re-validator (~> 0.3) was resolved to 0.4.0, which depends on
        Ruby (>= 2.6, < 4.0)

    rspec was resolved to 3.12.0, which depends on
      rspec-expectations (~> 3.12.0) was resolved to 3.12.2, which depends on
        diff-lcs (>= 1.2.0, < 2.0) was resolved to 1.5.0, which depends on
          Ruby (>= 1.8)

    web-push was resolved to 3.0.0, which depends on
      Ruby (>= 3.0)

  Current Ruby version:
    Ruby (= 2.7.6)

Bundler could not find compatible versions for gem "hkdf":
  In snapshot (Gemfile.lock):
    hkdf (= 1.0.0)

  In Gemfile:
    web-push was resolved to 1.0.0, which depends on
      hkdf (~> 0.2)

Deleting your Gemfile.lock file and running `bundle install` will rebuild your
snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.

Итак, я преодолел эту начальную ошибку, удалив файл блокировки, как и предлагалось, но затем столкнулся с NameError: undefined method ‘call’, о котором говорилось ранее. Исправил это, зафиксировав версию redis. После этого всё заработало.

Таким образом, мой скрипт был модифицирован так, чтобы: а) удалять Gemfile.lock (из-за ошибки, приведённой выше) и б) автоматически изменять Gemfile, фиксируя redis на версии 4.8.0. Всё должно было быть отлично… Так я думал. Это сработало на трёх из 20 «идентичных» машин! Остальные выдали новую ошибку:

[discourse@in3020-discourse discourse]$ cd $INSTA; RAILS_ENV=production /usr/local/bin/bundle exec rake db:migrate # stuffing a lot of stuff into the database
rake aborted!
NoMethodError: undefined method `logger=' for Sidekiq:Module
Did you mean?  logger
/var/discourse/config/initializers/100-sidekiq.rb:58:in `<main>'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/engine.rb:667:in `load'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/engine.rb:667:in `block in load_config_initializer'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.4.3/lib/active_support/notifications.rb:208:in `instrument'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/engine.rb:666:in `load_config_initializer'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/engine.rb:620:in `block (2 levels) in <class:Engine>'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/engine.rb:619:in `each'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/engine.rb:619:in `block in <class:Engine>'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:32:in `instance_exec'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:32:in `run'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:61:in `block in run_initializers'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:50:in `each'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:50:in `tsort_each_child'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:60:in `run_initializers'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/application.rb:372:in `initialize!'
/var/discourse/config/environment.rb:7:in `<main>'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/zeitwerk-2.6.7/lib/zeitwerk/kernel.rb:38:in `require'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/application.rb:348:in `require_environment!'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/railties-7.0.4.3/lib/rails/application.rb:511:in `block in run_tasks_blocks'
/var/discourse/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/exe/rake:27:in `<top (required)>'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/cli/exec.rb:58:in `load'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/cli/exec.rb:58:in `kernel_load'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/cli/exec.rb:23:in `run'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/cli.rb:486:in `exec'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/cli.rb:31:in `dispatch'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/cli.rb:25:in `start'
/usr/local/share/gems/gems/bundler-2.3.26/exe/bundle:48:in `block in <top (required)>'
/usr/local/share/gems/gems/bundler-2.3.26/lib/bundler/friendly_errors.rb:120:in `with_friendly_errors'
/usr/local/share/gems/gems/bundler-2.3.26/exe/bundle:36:in `<top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => db:migrate => db:load_config => environment
(See full trace by running task with --trace)

Это было действительно, очень странно, потому что файлы /var/discourse/config/initializers/100-sidekiq.rb были идентичны на всех машинах и определённо не содержали ‘logger=’, а лишь утверждение ‘logger = …’.

В конце концов я понял, что на машинах, где всё работало, /usr/local/bin/bundle был версии 2.3.20, а не 2.3.26, как на машинах, где произошла ошибка. Таким образом, в итоге добавление этого перед командой установки discourse сработало для меня (было недостаточно выполнить команды фиксации bundler на версии 2.3.20 после установки bundler для discourse; это должно было быть сделано до):

rm Gemfile.lock
perl -pi.bak -e 's/gem "redis"/gem "redis","4.8.0"/;' Gemfile

/usr/bin/gem uninstall bundler -v 2.3.26
/usr/bin/gem install bundler -v 2.3.20
RAILS_ENV=production /usr/local/bin/bundle install
RAILS_ENV=production /usr/local/bin/bundle exec rake db:migrate
RAILS_ENV=production /usr/local/bin/bundle exec rake assets:precompile

Почему на некоторых машинах был bundler 2.3.26, а на других 2.3.20, я понятия не имею… но это, вероятно, не ваша вина :laughing:.

Вот почему я использую стабильную версию :laughing:

Ruby 2.7 устарел (EOL) и больше не поддерживается нами. Вы не получите эту версию при установке Discourse по стандартному руководству уже довольно давно, поэтому я предполагаю, что у вас кастомная установка?

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

Да, официальный способ наверняка избавил бы меня от большинства (а то и всех) проблем. Дело в том, что я не могу использовать Docker-образы, не одобренные нашим отделом информационной безопасности, а ваш — не одобрен.

Поэтому это действительно кастомная нативная установка на машинах с RHEL8, которая потребовала некоторых ухищрений с SELinux для корректной работы.

Возможно, у других тоже возникла такая же проблема — может быть, им будет полезно, если я создам тему с описанием моей процедуры установки? Не стесняйтесь возразить — я понимаю, что это может быть воспринято как «поощрение» к такому способу установки, даже если он не является строго необходимым, что может привести к дополнительным вопросам к вам.

Кстати, при поиске решений любых проблем с SELinux в Google чаще всего советуют: «вот как его отключить» :laughing:. Но в нашем случае это не вариант.

Спасибо за вашу помощь!

Спасибо за предоставленную информацию. Обратите внимание, что мы не предоставляем бесплатную поддержку для кастомных установок.

Эта установка уже использует версию Ruby, которая несовместима ни с одной из текущих версий Discourse, игнорирует тщательно управляемые версии gem-пакетов и не использует все вручную управляемые системные библиотеки, которые мы поставляем. Поэтому сбои — это не вопрос «если», а вопрос «когда».

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

. . . . Но, скорее всего, это не поможет.

Ха-ха, да (с вашими изображениями, наверное, безопаснее) и нет (не очень полезно — но спасибо за комментарий всё равно :blush:).

Это действительно не моя основная работа. Я запускаю эти форумы «потому что я тот, кто может это сделать» в рамках пилотного проекта, чтобы убедить наш IT-отдел взять это на себя и развернуть для всего Университета Осло.

К счастью, похоже, это сработало, так что, надеюсь, это последний семестр, когда мне приходится вести всё это дело. Уверен, IT-отдел будет использовать изображения… :wink:

И спасибо, @Falco, что указал на несовпадение версий Ruby. Я займусь этим, если/когда столкнусь с проблемами при будущих обновлениях.

Ого! Будучи преподавателем в нескольких университетах США, я очень впечатлён.

Ой, забыл нажать кнопку «Ответить» на это сообщение давным-давно…

@pfaffman Ха-ха, да. Мы ещё не полностью вышли из зоны риска, даже если IT-отдел говорит, что всё в порядке: сначала нужно получить одобрение на самом верху (со стороны университетского совета) в качестве официального канала связи. К счастью, факультет естественных наук полностью поддержал нас и активно продвигал проект через все необходимые инстанции.

Я довольно горжусь тем, что смог запустить эти пилотные экземпляры — не многие люди, не работающие в IT-отделе, смогли бы это сделать (в рамках необходимых политик безопасности, разумеется). Сотрудники факультета естественных наук постоянно называют это «Astro-Discourse» (я работаю в Институте теоретической астрофизики) :laughing:.

Но теперь, похоже, мне придётся провести это шоу ещё один семестр с тем же нестандартным набором. Интересно, с какими версиями PostgreSQL совместима текущая версия Discourse?