2011-10-04 3 views
5

저는 Ruby 1.9.2를 사용하고 있습니다.데이터베이스 호출을하는 스레드에서 루비 타임 아웃 사용

정기적으로 데이터베이스를 호출하는 스레드가 있습니다. 호출은 꽤 길 수 있으며 DB 연결이 사라지는 (여러 가지 이유로) 경우가 있습니다. 그것이 사라지면, 그 쓰래드가 조용히 조용히 거기에 매달려 있습니다.

그래서이 문제를 처리하기 위해 시간 초과를 모두 감싸고 싶습니다. 문제는 타임 아웃을 호출해야하는 두 번째 시간 (항상 두 번째)에 여전히 간단하게 중단된다는 것입니다. 제한 시간은 적용되지 않습니다. 1.8에이 문제가 있다는 것을 알고 있지만 timeout.rb가 1.9에서 작동했다는 것을 알게되었습니다.

t = Thread.new do 
    while true do 
    sleep SLEEPTIME 
    begin 
     Timeout::timeout(TIMEOUTTIME) do 
     puts "About to do DB stuff, it will hang here on the second timeout" 
     db.do_db_stuff() 
     process_db_stuff() 
     end 
    rescue Timeout::Error 
     puts "Timed out" 
     #handle stuff here 
    end 
    end 
end 

왜 이런 일이 일어나고 있는지, 내가 어떻게 할 수 있습니까?

+0

그래서 Timeout :: Error가 발생하지 않습니다. 오류가 발생하고 있습니까? –

+0

맞습니다. 아무 일도 일어나지 않으며, 바로 그 곳에서 멈추게됩니다. 적어도, 실행을 다시 선택하는 경우 어디에서 실행할지 결정하기 위해 과도한'puts '을 두는 것으로 결정했습니다. –

+0

왜 던지기를하고 있을까요? 타임 아웃의 전체 시점은 주어진 블록이 너무 오래 실행되면 오류가 발생한다는 것입니다. datamapper와 mysql2를 직접 사용해 보았습니다. 자동으로 다시 연결하고 문제를 해결할 수 있기를 바랍니다.하지만 운이 없습니다. 세부 사항이 도움이된다면, 그것은'.query (...) '를 수행하는 mysql2 연결이라고 가정 해 봅시다. 어쨌든 그 곳에서 아무 것도 던지지 않으며, 그 밖의 일반적인'rescue' 절은 어떤 상황에서도 그것을 잡아 내야합니다. –

답변

5

하나의 가능성은 스레드가 멈추지 않는다는 것입니다. 실제로는 으로 끝납니다. 여기에 무슨 일이 일어나는지 알아 내기 위해해야 ​​할 일이 있습니다. 당신이 당신의 작업자 스레드 만들기 전에이 추가 : 예외가 잡힌되지 않습니다 스레드 내부에서 발생

Thread.abort_on_exception = true 

가, 전체 프로세스가 종료됩니다, 당신은 제기 된 예외를 볼 수 있습니다. 그렇지 않으면 (기본값이며) 스레드가 종료됩니다.

이 시간 초과

루비의 구현은 꽤 순진입니다 ... 읽어, 문제가 될하지을 밝혀합니다. n 초 동안 휴면 상태 인 별도의 스레드를 설정 한 다음 원래 스레드 내부에서 맹목적으로 시간 초과 예외를 발생시킵니다.

이제 원본 코드는 실제로 rescue 또는 ensure 블록 중간에있을 수 있습니다. 이러한 블록에서 예외를 발생 시키면 모든 종류의 정리 코드가 자동으로 중단됩니다. 이로 인해 시간이 초과 된 코드가 부적절한 상태가 될 수 있습니다.

이것이 정확히 문제인지는 알 수 없지만 데이터베이스 처리기가 잠금 및 예외 처리를 제대로 수행하는 방법을 확인하면 매우 어려울 수 있습니다. Here's an article that explains the issue in more depth.

데이터베이스 라이브러리의 기본 제공 시간 초과 처리를 사용할 수있는 방법이 있습니까? Ruby의 타임 아웃 구현을 사용하지 않고 하위 레벨에서 구현 될 수 있습니다.

간단한 대안은 별도의 프로세스에서 데이터베이스 호출을 예약하는 것입니다. 대량의 데이터베이스 리프팅을 수행 할 때마다 주 프로세스를 포크 할 수 있습니다. 또는 간단한 cronjob을 설정하여이를 실행하는 스크립트를 실행할 수도 있습니다. 주 스레드와 통신해야하는 경우이 작업이 약간 더 어려워집니다. 어떤 옵션이 귀하의 필요에 부합하는지 조언을 원하면 좀 더 자세히 기재하십시오.


사용자 의견에 따라 스레드가 죽어 가고 있습니다. 이는 라이브러리 또는 응용 프로그램 코드의 결함 일 수 있으며 수정하지 못할 수도 있습니다.당신이 함정에 데이터베이스 처리 코드에 의해 생성 이후에 다시 시도되는 임의의 오류를하고자하는 경우에는 다음과 같이 뭔가를 시도 할 수 있습니다 : 당신은 즉시 다시 시도 rescue 블록에서 retry 키워드를 사용할 수 있습니다

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 

, 그러나 복구 할 수없는 오류가 계속 발생하면 실수로 재 시도하지 않도록 카운터를 유지해야합니다.

+0

그것은 죽어가는 것처럼 보입니다. 지금은 내가 얻는 오류를 이해하지 못한다 :'구조 상 <필수 (필수)> ': 초기화되지 않은 상수 Object :: Error (NameError)' –

+0

참으로 죽어 가고 있지만, 지금은 내가 얻는 오류를 이해하지 못한다. :'구조 상 <필수 (필수)> ': 초기화되지 않은 상수 Object :: Error (NameError)'. 그럼에도 불구하고 어떻게 처리 할 수 ​​있습니까? db로부터 얻은 데이터는 coall 화되고 다른 것들과 합쳐져 서비스가 호출하므로이 스레드가 죽었을 때 또 다른 동일한 스레드를 생성 할 수 있기를 원합니다. 첫 번째 타임 아웃 이후에 항상 발생하기 때문에 타임 아웃 핸들러에서 스레드를 사전에 삭제할 수 있습니다. 다른 곳에서 스레드를 복제 할 수 있습니다. –

+0

잘 알고 있습니다! 이 예외의 원인을 찾아 수정하는 것이 가장 좋지만 이러한 예외를 잡아 내고 다시 시도하는 것으로 충분할 수 있습니다. 방법을 설명하기 위해 답변이 업데이트되었습니다. – molf