2008-09-17 3 views
17

WCF 서비스를 만들고 netMsmqBinding 바인딩을 사용하고 있습니다.WCF의 MSMQ 바인딩에서 메시지 오류를 처리하는 방법

이것은 Dto를 내 서비스 메소드로 전달하고 응답을 기대하지 않는 간단한 서비스입니다. 이 메시지는 MSMQ에 저장되고 일단 수집 된 데이터베이스에 삽입됩니다.

데이터가 손실되지 않도록하는 가장 좋은 방법은 무엇입니까?

나는이 다음과 같은 방법을 시도 :

  1. 이 수동 열람 죽은 레터 큐에 메시지를 배치 예외

    을 던져. 내 strvice 바인딩

    3 후 시도에 receiveRetryCount = "3"

  2. 세트를 시작할 때 나는이 문제를 처리 할 수 ​​- instantanously 일,이 큐에 메시지를 남겨,하지만 내 서비스를 잘못 것으로 보인다. 내 서비스를 다시 시작하면이 프로세스가 반복됩니다.

이상적으로는 추적을하고 싶습니다 :

시도 과정 메시지

  • 을이 실패하면, 해당 메시지 5 분 정도 기다렸다가 다시 시도하십시오.
  • 해당 프로세스가 세 번 실패하면 메시지를 배달 못 한 큐로 옮깁니다.
  • 서비스를 다시 시작하면 데드 레터 대기열의 모든 메시지가 대기열로 다시 보내져 처리됩니다.

이것을 수행 할 수 있습니까? 그렇다면 어떻게? 주어진 장면에 대해 WCF와 MSMQ를 가장 잘 활용하는 방법에 대한 좋은 기사를 가르쳐 주시겠습니까?

도움을 주시면 감사하겠습니다. 감사!

몇 가지 추가 정보

나는 불행하게도 나는 MSMQ 4.0 및 비스타/2008을 대상으로 포이즌 메시지 지원에 내장 사용할 수있는 Windows XP 및 Windows Server 2003 에 MSMQ 3.0을 사용하고 있습니다.

답변

9

사례에 유용 할 수있는 SDK의 샘플이 있습니다. 기본적으로, IERrorHandler 구현을 서비스에 첨부하면 WCF가 메시지를 "독"으로 선언 할 때 (즉, 구성된 모든 재시도 횟수가 고갈되었을 때) 오류를 catch합니다. 샘플이 수행하는 작업은 메시지를 다른 대기열로 이동 한 다음 메시지와 관련된 ServiceHost를 다시 시작하는 것입니다 (포이즌 메시지를 발견했을 때 오류가 발생했기 때문에).

아주 예쁜 샘플은 아니지만 유용 할 수 있습니다. 하지만 몇 가지 제한 사항이 있습니다.

1- 서비스와 연결된 여러 끝점 (여러 대기열을 통해 노출됨)이있는 경우 독이 들어오는 메시지가있는 대기열을 알 수있는 방법이 없습니다. 단일 대기열, 이것은 문제가되지 않습니다.나는 이것에 대한 공식적인 해결 방법을 보지 못했지만 여기에 문서화 한 가능한 대안을 실험 해 보았습니다. http://winterdom.com/weblog/2008/05/27/NetMSMQAndPoisonMessages.aspx

2- 일단 문제가 발생한 메시지가 다른 대기열로 옮겨지면 그 문제는 귀하의 책임이됩니다. 타임 아웃이 완료되면 처리 대기열로 다시 이동 (또는 처리를 위해 대기열에 새 서비스를 연결)해야합니다.

솔직하게 말해서 WCF가 자체적으로 다루지 않는 "수동"작업이 있습니다.

최근 재 시도 횟수를 명시 적으로 제어해야하는 다른 프로젝트에서 작업하고 있으며 현재 해결 방법은 재시도 대기열을 만들고 재시도 대기열과 주간 메시지를 수동으로 이동하는 것입니다 MSMQ 대기열을 처리하기 위해 원시 System.Messaging 항목 만 사용하여 타이머 및 일부 경험적 방법 집합을 기반으로 큐를 처리합니다. 이 방법을 사용하면 몇 가지 문제점이 있지만 꽤 잘 작동하는 것 같습니다.

14

난 당신이 이렇게 할 수있을 MSMQ (단 Vista에서 avaiable이다)으로 생각 :

<bindings> 
    <netMsmqBinding> 
     <binding name="PosionMessageHandling" 
      receiveRetryCount="3" 
      retryCycleDelay="00:05:00" 
      maxRetryCycles="3" 
      receiveErrorHandling="Move" /> 
    </netMsmqBinding> 
</bindings> 

WCF 바로 첫 번째 호출 실패 후 ReceiveRetryCount 시간에 대해 다시 시도합니다. 일괄 처리가 실패한 후 메시지는 재시도 대기열로 이동합니다. RetryCycleDelay 분 지연 후, 메시지가 재시도 대기열에서 엔드 포인트 대기열로 이동되고 배치가 재 시도됩니다. 이것은 MaxRetryCycle 시간으로 반복됩니다.모두 실패하면 메시지는 (포이즌 큐에), 거부, 삭제 또는 오류로 이동할 수있는 receiveErrorHandling에 따라 처리됩니다.

그런데 WCF 및 MSMQ에 대한 좋은 텍스트는 Progammig WCF 책의 9 번째 글입니다. Juval Lowy

+0

이 내용은 MSMQ 4.0이 아닌 MSMQ 3.0에 적용됩니다. – Perhentian

1

불행히도 저는 Windows XP와 Windows Server 2003에 붙어있어서 저에게는 옵션이 아닙니다. - (게시 한 후이 솔루션을 발견하여 그것을 사용할 수 없다는 것을 깨달았을 때 내 질문에 다시 설명 할 것입니다)

하나의 해결책은 내 메시지를 다른 대기열로 옮길 수있는 사용자 지정 처리기를 설정하는 것이 었습니다. 또는 포이즌 큐에 넣고 내 서비스를 다시 시작하십시오. 이것은 나에게 미친 것처럼 보였다. 내 Sql Server가 얼마나 자주 서비스가 다시 시작되는지 생각해보십시오.

그래서 내가 한 일은 라인에 오류를 허용하고 대기열에 메시지를 남기는 것입니다. 또한 시스템 로그인 서비스에 치명적인 메시지를 기록합니다. 문제가 해결되면 서비스를 다시 시작하면 모든 메시지가 다시 처리되기 시작합니다.

이 메시지를 다시 처리했거나 다른 메시지가 모두 실패 했으므로이 메시지와 다른 메시지를 다른 큐로 이동해야합니다. 나는 서비스를 멈추고 모두가 예상대로 작동 할 때 다시 시작할 수 있습니다.

aogan, 당신은 MSMQ 4.0에 대한 완벽한 대답을했지만, 불행히도 저

4

당신이 다음 MSMQ와 SQL-Server 지원이 모두 있기 때문에, 분산 트랜잭션을 사용한다 SQL-Server를 사용하는 경우. TransactionScope 블록에서 데이터베이스 쓰기를 래핑하고 성공할 경우에만 scope.Complete()를 호출합니다. 실패하면 WCF 메서드가 반환 될 때 메시지가 다시 시도하기 위해 큐에 다시 배치됩니다. 여기에 코드의 손질 버전은 내가 사용하는 것 : - 16 메시지

[OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)] 
    public void InsertRecord(RecordType record) 
    { 
     try 
     { 
      using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) 
      { 
       SqlConnection InsertConnection = new SqlConnection(ConnectionString); 
       InsertConnection.Open(); 

       // Insert statements go here 

       InsertConnection.Close(); 

       // Vote to commit the transaction if there were no failures 
       scope.Complete(); 
      } 
     } 
     catch (Exception ex) 
     { 
      logger.WarnException(string.Format("Distributed transaction failure for {0}", 
       Transaction.Current.TransactionInformation.DistributedIdentifier.ToString()), 
       ex); 
     } 
    } 

내가 많은 레코드 만 알려진 번호를 대기하여 테스트, WCF가 동시에 많이 처리 할 스레드를 많이 시작하자 (16 스레드에 도달 대기열에서 한 번에 꺼짐), 작업 중간에 프로세스를 종료합니다. 프로그램이 다시 시작되면 메시지는 대기열에서 다시 읽혀지고 아무 일도 일어나지 않은 것처럼 다시 처리됩니다. 테스트가 끝나면 데이터베이스는 일관되고 누락 된 레코드가 없습니다.

Distributed Transaction Manager는 주변에 존재하며 TransactionScope의 새 인스턴스를 만들면 메서드 호출 범위 내에서 현재 트랜잭션을 자동으로 검색합니다.이 트랜잭션은 이미 WCF에서 해당 트랜잭션을 팝했습니다 대기열에서 메시지를 보내고 메소드를 호출했습니다.

+0

안녕하세요. Chris. TransactionScopeRequired = true로 작업 동작을 지정하면 트랜잭션 범위에서 SQL 호출을 래핑 할 필요가 없으므로 트랜잭션 처리가 이미 완료된 것입니다. 그 말은, 당신의 대답이 MSMQ에 대한 나의 질문과 어떻게 관련이 있는지 잘 모르겠습니다. – WebDude

관련 문제