2011-08-31 5 views
1

동적으로 실행되는 기본 구성 요소가 프로세스 손상 상태 예외를 던져서 로깅 할 수 있고 구성 요소를 다시로드하기 좋지 않은 것으로 표시 할 때를 알 필요가 있습니다 내 과정을 망칠거야.Async.Catch를 사용하여 처리 상태가 손상된 처리 예외 처리

이 구성 요소의 실행은 비동기 적으로 수행되며 Async.Catch를 사용하여 해당 예외를 처리합니다. Async.Catch의 동작을 테스트하기 위해 다음 코드를 시도했는데 Async.Catch가 매달린 것 같습니다. 이것은 나에게 바람직하지 않은 영향이며 모든 PCSE가 동일한 동작을 초래할 것이라고 의심하고 있습니다.

누구나이 상황에서 벗어날 방법을 알고 계십니까?

let a = async { 
    System.Threading.Thread.CurrentThread.Abort() 
} 

let b = async { 
    let! m = Async.Catch a 
    return match m with 
      | Choice1Of2 p -> "hello" 
      | Choice2Of2 e -> "Caught: " + e.ToString() 
} 

Async.RunSynchronously b;; 

EDIT 1 : 나는 나를 중 하나 HandleProcessCorruptedStateExceptionsAttribute 함께 SecurityCriticalAttribute로 사용하거나 config 항목 legacyCorruptedState­­ExceptionsPolicy=true를 사용 가리키는 문서를 발견했다. 가능하다면 config 항목을 사용하고 싶지 않습니다.

편집 2 :

let b = async { 
     try 
      let! m = Async.Catch a 
      return "hello" 
     with 
      | :? System.Threading.ThreadAbortException as e -> return "Caught: " + e.ToString() 
    } 

프로그램은 여전히 ​​반환 또는 던지는없이 응답 : 주석의 제안을 바탕으로, 나는 다음과 같이 'B'에 대한 바인딩하자를 수정했습니다.

+0

하지 대답을,하지만 난 당신이 만드는/with' 대신 Async.Catch''의 시도'사용할 수 있다고 생각하여 비동기 블록이 더 읽기 쉽습니다. – kvb

+0

코드가 수정되었습니다 (EDIT2 참조). 여전히 동일한 동작입니다. –

+2

문제를 해결할 것이라고는 기대하지 않지만, '할 수 있도록하자!' m ='Async.Catch'를'try' 블록으로 옮기지 않고 "hello"를 리턴합니다. – kvb

답변

5

정상적인 기능을 사용하면 ThreadAbortException을 붙잡고 반응을 보이지만 실제로 처리 할 수는 없습니다. 자동으로 다시 처리되기 때문에 (결국 스레드가 죽을 것입니다).

F # async 워크 플로에서 예외가 처리되고 F # async 런타임은이를 저장하여 연속을 통해보고 할 수 있지만이 작업을 수행하기 전에 예외가 .NET에서 다시 발생하고 스레드 (따라서 RunSynchronously 중단).

문제는 예외를보고하기 위해 F # async에서 전화를해야합니다. 현재 스레드 (취소중인)에서 호출을 수행 할 수 없습니다. 예외가 예상되는 경우 스레드 풀에서 작업을 시작하고 직접 처리 할 수 ​​있습니다. (너무 많은 오버 헤드가 있기 때문에 F #은 자동으로 그렇게 할 수 없습니다).

type Microsoft.FSharp.Control.Async with 
    static member CatchAbort<'R>(f : unit -> 'R) : Async<'R> = 
    async { let hndl = new AutoResetEvent(false) 
      let result = ref (Choice3Of3()) 
      ThreadPool.QueueUserWorkItem(fun _ -> 
       try 
       result := Choice1Of3 (f()) 
       hndl.Set() |> ignore 
       with 
       | e -> 
        // This handler runs correctly even for ThreadAbort 
        result := Choice2Of3 e 
        hndl.Set() |> ignore) |> ignore 
      let! _ = Async.AwaitWaitHandle(hndl) 
      match !result with 
      | Choice1Of3(res) -> return res 
      | Choice2Of3(exn) -> 
       // Wrap or rethrow the exception in some way 
       return raise exn 
      | Choice3Of3 _ -> return failwith "unexpected case" } 

이 지정된 함수를 시작합니다 (비동기되지 않습니다) 스레드 풀 스레드에서 :

는 다음과 같은 도우미를 사용할 수 있습니다. 함수가 완료되거나 throw 된 후에는 결과를 원래 스레드로보고하고 워크 플로를 다시 시작할 수 있습니다.

귀하의 예를 적용하려면이 예상대로 작동한다 : 당신의 질문에

let a = async { 
    let! value = Async.CatchAbort(fun() -> 
     System.Threading.Thread.CurrentThread.Abort() 
     "not aborted") 
    return value } 

let b = async { 
    try let! m = a 
     printfn "ok" 
    with e -> printfn "Caught: %A" e } 
+0

대단한 답변에 감사드립니다. 내 주요 요구 사항은 비동기 함수 내부에서 발생하는 모든 프로세스 손상 상태 예외를 처리하는 것입니다. 따라서 응답에서 언급 한 이유로 콜백에서 예외가 발생했음을보고하지 않는 비동기 워크 플로 문제가 여전히 발생합니다. BTW, 예를 들어 스레드 중단을 사용하고있었습니다. 이제 막달레나 한 상황에서 복구해야 할 유일한 방법은 타이머를 설정하고 내 비동기 워크 플로가 알 수없는 이유 때문에 멈추었다 고보고하고 프로세스를 중단하는 것입니다. 공정한? –

+0

다른 PCSE 예외가 어떻게 작동하는지 모르겠지만 비슷한 방법으로 스레드를 종료한다고 가정하므로 차이가 없어야합니다. 당신은 당신이 외부 컴포넌트를 호출한다고 언급한다. 나는이 컴포넌트가 F #로 작성되지 않았으며 비동기 워크 플로를 사용하지 않는다고 가정한다. 따라서 나의 예제에서와 같이'CatchAbort'를 사용하여 비동기로 래핑 할 수 있어야한다. –

+0

F # async 워크 플로가 내부적으로 catch를 시도하고보고하기 때문에이 추가 줄 바꿈을 사용하지 않으면 예외를 catch 할 수 없습니다 (스레드가 종료되면 불가능 함). –

3

읽을 수 있습니다. here - ThreadAbortException은 CLR의 특별한 예외 중 하나입니다. Asycn-Pattern을 꽤 열심히 깨뜨린 것 같습니다. 그래서 그것이 여기에있는 문제입니다.

또 다른 예외를 시도해보고 정상적으로 작동하는지 확인하십시오.

+0

설명서 스레드가 종료되기 전에 finally 블록이 실행될 것이라고 나와 있으며 비동기 워크 플로를 정상적으로 처리 할 것으로 예상합니다. . 더욱이, 나를 귀찮게하는 것은 그 과정이 심지어 충돌하지 않을 것이지만, 매달릴 것입니다. 나는 콜백이이 예외로 인해 호출 된 적이 없다고 생각한다. 그러나 이것이 비동기 워크 플로의 버그가 아니겠습니까? –

+1

또는 (문서 힌트로) 첫 번째 TAE가 다른 것으로 변환되고 공통 런타임은 다시 태핑하지 않고 스레드를 다른 방법으로 종료합니다. * 비동기의 모든 try/catch (with)는 docs에서 계산 워크 플로로 읽을 수있는대로 * normal * try/catch와 다릅니다. 하지만 저는 전문가가 아니지만 이것이 당신 문제라고 생각합니다. 나는 다른 경우에 유사한 경험을했다 - TAE, StackOverflow 등과 같은 예외는 항상 문제이며 이러한 경우에 앱을 종료하는 것이 일반적으로 더 좋다. 지금까지는 항상 얼버무 리지 않고 일할 수있는 재 설계를 찾았습니다 – Carsten