Возможно, что ваш поток не зависает, на самом деле умирает . Вот что вы должны сделать, чтобы выяснить, что происходит. Добавьте это, прежде чем создавать свой рабочий поток:
Thread.abort_on_exception = true
Когда в вашем потоке возникает исключение, которое никогда не перехватывается, весь ваш процесс завершается, и вы видите, какое исключение было вызвано. В противном случае (и это по умолчанию) ваш поток уничтожается.
Если выясняется, что проблема не , читайте дальше ...
Реализация тайм-аутов в Ruby довольно наивна. Он устанавливает отдельный поток, который спит в течение n секунд, а затем вслепую вызывает исключение Timeout внутри исходного потока.
Теперь исходный код может фактически находиться в середине блока rescue
или ensure
. Вызов исключения в таком блоке молча прервет любой вид кода очистки. Это может привести к превышению времени ожидания кода в неправильном состоянии.
Довольно сложно сказать, является ли это именно вашей проблемой, но, видя, как обработчики базы данных могут выполнять значительную часть блокировок и обработки исключений, это может быть весьма вероятным. Вот статья, которая более подробно объясняет проблему .
Есть ли способ использовать встроенную обработку тайм-аутов вашей библиотеки базы данных? Это может быть реализовано на более низком уровне, без использования реализации времени ожидания Ruby.
Простая альтернатива - это планирование вызовов базы данных в отдельном процессе. Вы можете разветвлять основной процесс каждый раз, когда выполняете тяжелый подъем базы данных. Или вы можете настроить простой cronjob для выполнения скрипта, который его выполняет. Это будет немного сложнее, если вам нужно общаться с вашим основным потоком. Пожалуйста, оставьте некоторые подробности, если вам нужен совет, какой вариант может удовлетворить ваши потребности.
Судя по вашим комментариям, тема умирает. Это может быть ошибка в библиотеках или коде приложения, которую вы можете или не сможете исправить. Если вы хотите перехватить любую произвольную ошибку, сгенерированную кодом обработки базы данных, и затем повторить попытку, вы можете попробовать что-то вроде следующего:
t = Thread.new do
loop do
sleep INTERVAL
begin
# Execute database queries and process data
rescue StandardError
# Log error or recover from error situation before retrying
end
end
end
Вы также можете использовать ключевое слово retry
в блоке rescue
, чтобы повторить попытку немедленно, но вам, вероятно, следует сохранить счетчик, чтобы избежать случайных повторных попыток в течение неопределенного времени при возникновении неисправимой ошибки.