У меня есть некоторый код, метод класса для класса Ruby FootballSeries.find(123)
, который выполняет вызов API… из-за опасений по поводу безопасности потока, только один поток может войти в этот метод одновременно.В связи с некоторыми недавними изменениями в API, я также поддержал следующее… FootballSeries.find('Premiership')
, второй вариант (см. Реализацию ниже) просто выполняет промежуточный вызов, чтобы проверить, можно ли найти идентификатор, а затем рекурсивно вызывает себя с использованием идентификатора..
class FootballSeries
@find_mutes = Mutex.new
class << self
def find(series_name_or_id)
@find_mutex.synchronize do
if series_name_or_id.is_a?(String)
if doc = search_xml_document(series_name_or_id)
if doc.xpath('//SeriesName').try(:first).try(:content) == series_name_or_id
@find_mutex.unlock
series = find(doc.xpath('//seriesid').first.content.to_i)
@find_mutex.lock
return series
end
end
elsif series_name_or_id.is_a?(Integer)
if doc = xml_document(series_name_or_id)
Series.new(doc)
end
end
end
end
end
end
Без строк 9 и 11 возникает ошибка recursive mutex lock: deadlock
(которая имеет достаточно смысла… поэтому мой вопрос, могу ли я разблокировать и повторно заблокировать мьютекс. (Я повторно блокирую, так чточто при выходе synchronize
я не получу сообщение об ошибке разблокировки мьютекса, который мне не принадлежит… но я не проверял, требуется ли это)
Это нормальная реализация,или лучше бы мне, если бы find()
вызывал два отдельных метода, каждый из которых был защищен своим собственным мьютексом? (пример find_by_id
и find_by_name
)
То, что у меня сейчас работает (или нанаименьшее количество работает).
Наконец, бонусные баллы за - как бы я протестировал такой метод на безопасность?