はじめに
Railsで並列処理をしたところ困ったことがあったのでまとめておきます
問題
以下のようにスレッドでfetch_dataをするような処理を書きました
def self.where(ids:)
threads = []
results = []
mutex = Mutex.new
ids.each do |id|
threads << Thread.new do
result = fetch_data(id)
mutex.synchronize do
results << result
end
end
end
threads.each(&:join)
results
end
private_class_method
def self.fetch_data(id)
api_response = SomeAPI.get(id)
record = SmapleActiveRecord.find(id) # ActiveRecordから取得
return nil if api_response.nil?
data = {
name: api_response['name'],
description: api_response['description'],
country: api_response['country'],
tags: api_response['tags'],
record: record
}
end
しかし、record = SmapleActiveRecord.find(id)
の部分でデータが取得できませんでした
スレッドの中に入るとデータベースからデータがうまく取れないようです
解決方法
並列化の中ではコネクションの関係でアクティブレコードからデータが取れなかったので、アクティブレコードの取得部分だけをスレッドの外で行うようにしました
def self.where(ids:)
threads = []
mutex = Mutex.new
results = {}
ids.each do |global_id|
threads << Thread.new do
api_response = SomeAPI.get(id)
return nil if company_response.nil?
result = {}
company["some_api"] = api_response
mutex.synchronize do
results[id] = result
end
end
end
threads.each(&:join)
responses = results.compact
ids.map { |_id|
record = SmapleActiveRecord.find(id)
new(
name: api_response['name'],
description: api_response['description'],
country: api_response['country'],
tags: api_response['tags'],
record: record
)
}
end
おわりに
解決方法は単純ですが、コネクションを気にせず解決したい場合はこの方法で対応できます。