#ruby-on-rails #design-patterns #refactoring #sidekiq
#ruby-on-rails #шаблоны проектирования #рефакторинг #sidekiq
Вопрос:
В моем приложении Rails я использую sidekiq для планирования заданий для выполнения тяжелых задач. Итак, у меня есть этот код во многих местах:
if Rails.env.development? or Rails.env.test?
#Call the method directly
else #Rails.env.production?
#Call the job via sidekiq that calls the said method
end
Есть ли какой-нибудь способ очистить это? В наши дни я читаю шаблоны проектирования программного обеспечения. Я не могу применить эти знания здесь. Можете ли вы предложить, как это можно очистить или написать более управляемым способом?
Комментарии:
1. Общего ответа нет — это зависит от характера вызываемого, является ли оно частью иерархии классов и т. Д. Похоже, что какая-то форма микширования может обернуть это, например, форма
sidekiqable :the_method
оболочки.2. Вы думали об использовании just jobs? Вы можете установить разные исполнители заданий в соответствии с вашим env (sidekiq для prod, async для dev и test для test) для достижения аналогичного поведения, и было бы меньше кода, специфичного для среды, который менее подвержен ошибкам. Я предполагаю, что прямо сейчас ваши тесты проверяют вызовы методов, но что произойдет, если ваша работа изменится, и вы забудете обновить? Все тесты проходят, но ваш фактический производственный код прерывается.
Ответ №1:
Вы можете поместить
require 'sidekiq/testing'
Sidekiq::Testing.inline!
в ваших development.rb
и test.rb
конфигурационных файлах, чтобы получить поведение, которое вам нужно. В бизнес-логике ваших приложений вы должны удалить условие среды и просто вызвать worker (который теперь будет выполняться синхронно при тестировании и разработке).
Ответ №2:
Как насчет того, чтобы попробовать рефакторинг следующим образом?
module Util
extend self
def execute_method_or_delay_its_execution(obj:, method_name:)
if Rails.env.development? or Rails.env.test?
obj.send(method_name)
else #Rails.env.production?
#Call the job via sidekiq that calls the said method
end
end
end
MyClass1
def my_method
Util.execute_method_or_delay_its_execution(obj: self, method_name: :my_method)
end
end
MyClass2
def my_method
Util.execute_method_or_delay_its_execution(obj: self, method_name: :my_method)
end
end
а затем просто вызовите методы для объекта, как и должно быть, и внутреннее делегирование должно позаботиться о желаемом прямом выполнении или отложенном выполнении
mc_1 = MyClass1.new
mc_1.my_method
mc_2 = MyClass2.new
mc_2.my_method
Надеюсь, это поможет. Спасибо.
Комментарии:
1. Наличие условия, которое вызывает метод, прямо противоположный прохождению через worker, является очень опасной игрой, если ваша команда инженеров не очень в курсе событий, потому что методы / сервисы будут взаимодействовать по-разному в зависимости от вашей среды. Например, при производстве результатом этого метода будет строка (задание sidekiq), тогда как при разработке / тестировании результатом этого метода будет все, что возвращает отправленный метод.