Потоки 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, они создали надежный процесс параллельного выполнения заданий, готовый к работе и простой в настройке.

Посмотрите их " Начало работы", чтобы убедиться в этом сами.

Другие вопросы по тегам