Я продолжаю получать противоречивые мнения о практике хранения информации в хеше Thread.current
(например, current_user, текущий поддомен и т.д.). Этот метод был предложен как способ упростить последующую обработку на уровне модели (область охвата запроса, аудит и т.д.).
Многие считают практику неприемлемой, поскольку она нарушает шаблон MVC.
Другие выражают озабоченность по поводу надежности/безопасности подхода, и мой вопрос из двух частей посвящен второму аспекту.
-
Является ли хэш Thread.current
гарантированным доступным и конфиденциальным для одного и только одного ответа на протяжении всего цикла?
-
Я понимаю, что поток, в конце ответа, вполне может быть передан другим входящим запросам, тем самым утечка любой информации, хранящейся в Thread.current
. Будет ли устранение такой информации до конца ответа (например, путем выполнения Thread.current[:user] = nil
с контроллера after_filter
) для предотвращения такого нарушения безопасности?
Спасибо!
Giuseppe
Ответ 1
Не существует конкретной причины, чтобы держаться подальше от локальных переменных, основными проблемами являются:
- сложнее их протестировать, так как вам придется не забывать устанавливать локальные переменные потока при тестировании кода, который его использует.
Классы
- которые используют локаторы потоков, нуждаются в знаниях о том, что эти объекты не являются доступными для них, но внутри локальной переменной потока, и этот тип косвенности обычно нарушает закон demeter
- не очистка локаторов потоков может быть проблемой, если ваша инфраструктура повторно использует потоки (уже была инициирована локальная переменная потока, а код, который полагается на || =, вызовы для инициализации переменных могут завершиться неудачно
Итак, хотя это не совсем возможно, подход лучший не использует их, но время от времени вы попадаете в стену, где локальный поток будет самым простым возможное решение, не изменяя довольно много кода, и вам придется идти на компромисс, иметь менее совершенную объектно-ориентированную модель с потоком локального или менять довольно много кода, чтобы сделать то же самое.
Итак, это в основном вопрос мышления, который будет лучшим решением для вашего дела, и если вы действительно сходите по нит-локальному пути, я бы посоветовал вам сделать это с блоками, которые помнят очистите их после завершения, например:
around_filter :do_with_current_user
def do_with_current_user
Thread.current[:current_user] = self.current_user
begin
yield
ensure
Thread.current[:current_user] = nil
end
end
Это гарантирует, что локальная переменная потока очищается до использования, если этот поток повторно используется.
Ответ 2
Этот маленький жемчуг гарантирует, что локальные переменные потока/запроса не встанут между запросами: https://github.com/steveklabnik/request_store
Ответ 3
Принятый ответ технически точен, но как указано в ответе мягко, а http://m.onkey.org/thread-safety-for-your-rails не так мягко:
Не используйте локальное хранилище потоков Thread.current
, если вам не нужно
Драгоценный камень для request_store
- это еще одно решение (лучше), но просто прочитайте readme там по другим причинам, чтобы держаться подальше от локального хранилища потоков.
Существует почти всегда лучший способ.