Потоки Ruby не работают после обновления до Rails 5
У меня есть API, который использует службу, в которой я использовал поток Ruby, чтобы уменьшить время отклика API. Я попытался поделиться контекстом, используя следующий пример. Он отлично работал с Rails 4, ruby 2.2.1
Теперь мы обновили rails до 5.2.3 и Ruby 2.6.5. После чего служба перестала работать. Я могу вызвать сервис из консоли, все работает нормально. Но при вызове API служба перестает отвечать, как только достигает CurrencyConverter.new. Любая идея, в чем может быть проблема?
class ParallelTest
def initialize
puts "Initialized"
end
def perform
# Our sample set of currencies
currencies = ['ARS','AUD','CAD','CNY','DEM','EUR','GBP','HKD','ILS','INR','USD','XAG','XAU']
# Create an array to keep track of threads
threads = []
currencies.each do |currency|
# Keep track of the child processes as you spawn them
threads << Thread.new do
puts currency
CurrencyConverter.new(currency).print
end
end
# Join on the child processes to allow them to finish
threads.each do |thread|
thread.join
end
{ success: true }
end
end
class CurrencyConverter
def initialize(params)
@curr = params
end
def print
puts @curr
end
end
Если я удалю CurrencyConverter.new(валюта), все будет работать нормально. CurrencyConverter - это служебный объект, который у меня есть.
Обнаружил проблему. Спасибо @anothermh за эту ссылку https://guides.rubyonrails.org/threading_and_code_execution.htmlhttps://guides.rubyonrails.org/threading_and_code_execution.html
Согласно блогу, когда один поток выполняет автозагрузку, оценивая определение класса из соответствующего файла, важно, чтобы ни один другой поток не встретил ссылку на частично определенную константу.
Только один поток может загружаться или выгружаться одновременно, и для этого он должен дождаться, пока ни один из других потоков не запустит код приложения. Если поток ожидает выполнения загрузки, это не препятствует загрузке других потоков (фактически, они будут сотрудничать, и каждый будет выполнять свою очередь загрузки по очереди, прежде чем все возобновят работу вместе).
Это можно решить, разрешив одновременные нагрузки. https://guides.rubyonrails.org/threading_and_code_execution.html
Rails.application.executor.wrap do
urls.each do |currency|
threads << Thread.new do
CurrencyConverter.new(currency)
puts currency
end
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
threads.map(&:join)
end
end
end
Спасибо всем за ваше время, я ценю.
1 ответ
Не изобретайте колесо заново, а вместо этого используйте Sidekiq.
Со страницы проекта:
Простая и эффективная фоновая обработка для Ruby.
Sidekiq использует потоки для одновременной обработки множества заданий в одном процессе. Он не требует Rails, но будет тесно интегрирован с Rails, чтобы сделать фоновую обработку чрезвычайно простой.
Имея более 400 участников и более 10 тысяч запусков на Github, они создали надежный процесс параллельного выполнения заданий, готовый к работе и простой в настройке.
Посмотрите их " Начало работы", чтобы убедиться в этом сами.