[ruby-on-rails] Rails에서 Thread.current [] 사용의 안전성

Thread.current해시 (예 : current_user, 현재 하위 도메인 등)에 정보를 저장하는 관행에 대해 상충되는 의견을 계속 받고 있습니다. 이 기술은 모델 계층 (쿼리 범위 지정, 감사 등) 내에서 이후의 처리를 단순화하는 방법으로 제안되었습니다.

많은 사람들은 MVC 패턴을 깨뜨리기 때문에 이러한 관행을 받아 들일 수 없다고 생각합니다. 다른 사람들은 접근 방식의 신뢰성 / 안전성에 대해 우려를 표명하고 2 부로 구성된 질문은 후자 측면에 중점을 둡니다.

  1. 는 IS Thread.current해시는 전체주기 동안, 오직 하나의 응답 가능하고 개인이 보장?

  2. 응답이 끝날 때 스레드가 다른 수신 요청으로 전달되어에 저장된 정보가 유출 될 수 있음을 이해합니다 Thread.current. 대응이 끝나기 전에 그러한 정보를 지우는 것만으로도 (예 : Thread.current[:user] = nil컨트롤러에서 실행 하여 after_filter) 보안 위반을 방지 할 수 있습니까?

감사! 주세페



답변

스레드 로컬 변수에서 벗어나야하는 특별한 이유는 없습니다. 주요 문제는 다음과 같습니다.

  • 이를 사용하는 코드를 테스트 할 때 스레드 로컬 변수를 설정해야하므로 테스트하기가 더 어렵습니다.
  • 스레드 로컬을 사용하는 클래스는 이러한 개체를 사용할 수 없지만 스레드 로컬 변수 내부에 있다는 지식이 필요 하며 이러한 종류의 간접 지정은 일반적 으로 데 미터법칙을 위반합니다.
  • 프레임 워크가 스레드를 재사용하는 경우 스레드 로컬을 정리하지 않는 것이 문제가 될 수 있습니다 (스레드 로컬 변수가 이미 시작되고 변수 초기화를 위해 || = 호출 에 의존하는 코드 가 실패 할 수 있음)

따라서 사용하는 것이 완전히 의문의 여지 가 없지만 가장 좋은 방법은 사용하지 않는 것이지만 때때로 스레드 로컬이 상당히 많은 코드를 변경하지 않고도 가능한 가장 간단한 솔루션이 될 벽에 부딪 히게됩니다. 당신은 타협해야 할 것이고, 스레드 로컬로 완벽하지 않은 객체 지향 모델을 가지고 있거나 똑같이하기 위해 꽤 많은 코드를 변경해야합니다.

따라서 그것은 대부분 귀하의 경우에 가장 적합한 솔루션이 될 것이라고 생각하는 문제이며 실제로 스레드 로컬 경로를 따라 내려가는 경우 다음 정리를 기억하는 블록으로 수행하도록 조언합니다. 다음과 같이 완료됩니다.

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

이렇게하면이 스레드가 재활용되는 경우 사용하기 전에 스레드 로컬 변수가 정리됩니다.


답변

이 작은 gem은 스레드 / 요청 로컬 변수가 요청 사이에 고정되지 않도록합니다 : https://github.com/steveklabnik/request_store


답변

받아 들여진 대답은 질문을 다루지 만 Rails 5는 이제 Thread.current를 사용 하는 “Abstract super class” ActiveSupport :: CurrentAttributes 를 제공합니다.

가능한 ( 인기없는 ) 솔루션 으로 링크를 제공 할 것이라고 생각했습니다 .

https://github.com/rails/rails/blob/master/activesupport/lib/active_support/current_attributes.rb


답변

허용되는 답변은 기술적으로 정확하지만 답변에서 부드럽게 지적하고 http://m.onkey.org/thread-safety-for-your-rails 에서 그렇게 부드럽게 지적 하지 않습니다.

Thread.current꼭 필요하지 않은 경우 스레드 로컬 저장소를 사용하지 마십시오.

에 대한 gem request_store은 또 다른 솔루션 (더 나은)이지만 스레드 로컬 저장소에서 멀리 떨어져 있어야하는 더 많은 이유 때문에 readme를 읽으십시오.

거의 항상 더 나은 방법이 있습니다.


답변