Foundations

워크플로의 오류 처리

Matt Milner

코드는 MSDN 코드 갤러리에서 다운로드할 수 있습니다.
온라인으로 코드 찾아보기

목차

워크플로의 오류 처리
호스트 프로세스의 오류 처리
사용자 지정 작업의 오류 처리
보정 사용
Retry 작업

Windows WF(Workflow Foundation)는 기능이 풍부한 비즈니스 프로세스와 이러한 프로세스 실행 및 관리를 위한 런타임 환경을 정의하는 도구를 제공합니다. 모든 비즈니스 프로세스의 예상 실행 흐름에는 예외가 발생하며 개발자는 이러한 예외로부터 복구하는 안정적인 응용 프로그램 논리를 작성할 수 있어야 합니다. 기술 샘플에서는 대부분 오류 처리나 올바른 복구를 간과하는 경향이 있습니다. 이달의 칼럼에서는 WF 프로그래밍 모델의 여러 수준에서 예외를 올바르게 처리하는 방법을 소개하고 워크플로와 호스트에 풍부한 예외 처리 기능을 추가하는 방법을 알아보겠습니다.

워크플로의 오류 처리

비즈니스 프로세스를 개발하는 개발자는 프로세스가 탄력적으로 작동하고 오류가 발생하더라도 실행을 계속할 수 있도록 비즈니스 사례의 예외를 처리할 수 있어야 합니다. 이것은 장기 실행 프로세스를 정의하는 경우가 많고 오류를 처리하지 않으면 대부분 프로세스를 다시 시작해야 하는 워크플로의 경우에 특히 중요합니다. 워크플로 내에서 예외가 발생하고 처리되지 않으면 워크플로가 종료되는 것이 워크플로의 기본 동작입니다. 따라서 워크플로 개발자는 올바르게 작업 범위를 지정하고, 오류를 처리하며, 오류가 발생하면 작업을 다시 시도하는 기능을 워크플로에 추가해야 합니다.

워크플로에서 오류를 처리하는 것은 Microsoft .NET Framework 대상 코드에서 오류를 처리하는 것과 공통점이 많으며 몇 가지 새로운 개념이 적용됩니다. 오류를 처리하는 첫 번째 단계는 실행 범위를 정의하는 것입니다. .NET 코드에서는 이 작업에 try 키워드를 사용합니다. 워크플로에서는 대부분의 복합 작업을 사용하여 예외 처리 범위를 만들 수 있습니다. 각 복합 작업에는 자식 작업을 표시하는 주 보기가 있으며 대체 보기도 있습니다. Sequence 작업에 대한 상황에 맞는 메뉴인 그림 1에는 다양한 보기에 액세스하는 방법과 오류 핸들러 보기 옵션을 선택했을 때의 결과가 나와 있습니다.

fig01.gif

그림 1 대체 보기 메뉴 및 오류 핸들러 보기 선택

오류 핸들러 보기로 전환하면 Sequence 작업의 작업 컬렉션에 FaultHandlers 작업이 추가됩니다. FaultHandlers 작업 내에서 개별 FaultHandler 작업을 추가할 수 있습니다. 각 FaultHandler 작업에는 오류 유형과 .NET의 catch 식과 같은 작업을 정의하는 속성이 있습니다.

FaultHandler 작업은 워크플로 개발자가 예외를 처리하는 방법을 정의하는 자식 작업을 추가할 수 있도록 허용하는 복합 작업입니다. 이러한 작업은 오류 기록, 관리자 연락 또는 코드에서 예외를 처리할 때 일반적으로 수행하는 다른 작업과 같은 기능을 제공할 수 있습니다.

FaultHandler 작업에는 포착된 예외를 포함하는 Fault 속성도 있습니다. 자식 작업은 이 속성에 바인드하여 예외에 액세스할 수 있습니다. 이러한 예가 그림 2에 나와 있으며 여기에서는 사용자 지정 로깅 작업의 exception 속성이 FaultHandler 작업의 Fault 속성에 바인딩되어 있음을 알 수 있습니다. 로깅 작업은 이제 예외 정보를 로깅 API, Windows 이벤트 로그, WMI(Windows Management Instrumentation) 또는 다른 대상에 기록할 수 있습니다.

그림 2 Fault에 바인딩

catch 블록과 비슷하게 FaultHandler 작업은 해당 오류 유형을 바탕으로 평가됩니다. 워크플로를 정의할 때는 FaultHandler 작업을 FaultHandlers에 가장 세부적인 오류부터 가장 일반적인 오류 순으로 왼쪽에서 오른쪽으로 추가해야 합니다.

fig03.gif

그림 3 복합 이후 실행 진행

예외가 발생하고 .NET 코드에서 포착되면, catch 블록이 실행을 완료한 후에 try 범위 이후에 실행이 계속됩니다. 즉, 워크플로에서 예외를 처리하는 복합 작업이 실행된 후에는 다음 작업에서 실행이 계속됩니다.

FaultHandler 작업의 평가 및 실행과 관련된 두 가지 핵심적인 개념이 있습니다. 그림 3과 같이 Throw 작업이 실행되거나 다른 작업이 예외를 발생시키면 런타임은 작업을 Faulted 상태로 설정하고 작업의 HandleFault 메서드를 실행하도록 예약합니다. 작업이 이 메서드를 구현하는 방법에 대한 자세한 내용은 조금 뒤에 설명할 것입니다. 현재로서는 작업이 정리할 수 있는 기회라는 정도만 알아두십시오.

작업이 정리를 완료하고 Closed 상태로 전환될 때, 부모 작업은 Faulting 상태로 전환되며, 마찬가지로 모든 자식 상태를 정리할 기회를 얻고, 종료 상태로 전환될 준비가 되었다는 신호를 보냅니다. 이 시점에 복합 작업은 Closed 상태로 전환될 준비가 되었다는 신호를 보내고, 런타임이 상태를 확인하며, Faulting 상태일 경우 FaultHandlers 컬렉션을 검사합니다. Fault 유형이 현재 예외와 일치하는 FaultHandler 작업이 발견되면 해당 FaultHandler가 예약되고 평가가 중지됩니다. FaultHandler가 종료되면 다음 작업에서 실행이 계속될 수 있습니다.

예외가 발생하면 런타임은 직계 부모 복합 작업에서 오류 처리 작업을 찾으려고 시도합니다. 일치하는 처리기가 발견되지 않으면 해당 복합이 Faulted이고 트리의 다음 복합 작업으로 예외가 전달됩니다. 이것은 .NET 예외가 처리되지 않을 때 스택에서 호출 메서드로 전달되는 것과 비슷합니다. 예외가 워크플로의 루트 작업까지 전달되었지만 처리기가 없는 경우 워크플로가 종료됩니다.

워크플로 자체도 복합 작업이므로 최상위 수준에 도달한 예외를 처리하기 위한 오류 처리 논리를 정의할 수 있습니다. 이것은 워크플로 개발자가 비즈니스 프로세스에서 예외를 포착하고 처리할 수 있는 마지막 기회입니다.

호스트 프로세스의 오류 처리

안정적인 워크플로를 만드는 것도 중요하지만 호스트가 예외를 처리할 수 있도록 하는 것도 응용 프로그램의 안정성을 위해 마찬가지로 중요합니다. 다행스럽게도 워크플로 런타임은 기본적으로 이러한 예외를 안정적으로 처리할 수 있으며 대부분의 예외가 전달되지 않도록 호스트 프로세스를 보호할 수 있습니다.

워크플로에서 예외가 발생할 때 계층을 통해 예외가 전달되고 포착되지 않으면 워크플로가 종료되고 런타임에 이벤트가 발생합니다. 런타임의 호스트는 이러한 예외가 발생하면 알림을 받도록 처리기를 등록할 수 있지만 예외는 호스트가 충돌하는 원인은 아닙니다. 이러한 종료에 대한 알림을 받으려면 호스트 프로세스에서 다음과 같은 코드를 사용하여 이벤트 인수로부터 예외에 대한 정보를 얻을 수 있습니다.

workflowRuntime.WorkflowTerminated += delegate(
  object sender, WorkflowTerminatedEventArgs e)
{
  Console.WriteLine(e.Exception.Message);
};

종료된 워크플로를 처리하는 것 외에도 호스트 프로세스에는 런타임 서비스에서 발생한 예외에 대한 알림을 받는 기능이 있습니다. 예를 들어 SqlWorkflowPersistence­Service는 런타임으로 로드되면 데이터베이스를 폴링하고 추가 작업이 있으면 주기적으로 워크로드 로드를 시도할 수 있습니다. 워크플로 로드를 시도할 때 지속성 서비스는 예를 들어 워크플로를 역직렬화하려고 시도할 때 예외를 발생시킬 수 있습니다. 이 경우 호스트 프로세스에서 오류가 발생하지 않도록 하는 것이 중요하므로 이러한 서비스는 이러한 예외를 다시 발생시키지 않고 대신 워크플로 런타임에 대해 이벤트를 발생시킵니다. 그러면 런타임은 다음과 같이 코드에서 처리할 수 있는 ServicesExceptionNotHandled 이벤트를 발생시킵니다.

workflowRuntime.ServicesExceptionNotHandled += delegate(
  object sender, ServicesExceptionNotHandledEventArgs snhe)
{
  Console.WriteLine(snhe.Exception.Message);
};

일반적으로 런타임 서비스 개발자는 예외를 포착할 때 예외가 중요한지 결정해야 합니다. SqlWorkflowPersistenceService의 경우 워크플로 하나를 로드할 수 없다고 해서 서비스가 작동할 수 없게 되는 것은 아닙니다. 따라서 이 경우에는 호스트 프로세스가 추가 작업이 필요한지 결정할 수 있도록 이벤트를 발생시키는 것이 합리적입니다. 그러나 지속성 서비스가 SQL Server 데이터베이스에 연결할 수 없는 경우에는 아예 작동이 불가능합니다. 이 경우에는 이벤트를 발생시키기보다는 문제가 해결될 수 있도록 서비스가 예외를 발생시키고 호스트를 중지시키는 것이 더 합리적입니다.

사용자 지정 런타임 서비스를 개발할 때는 이러한 서비스를 WorkflowRuntimeService 기본 클래스에서 파생시키는 것이 좋습니다. 이 기본 클래스는 ServicesExceptionNotHandled 이벤트를 발생시키기 위한 런타임과 보호된 메서드에 대한 액세스를 제공합니다. 런타임 서비스 실행 중에 예외가 발생하면 서비스는 이것이 복구 불가능한 오류인 경우에만 예외를 발생시켜야 합니다. 반면에 오류가 단일 워크플로 인스턴스와 관련된 것이고 서비스의 일반적인 실행과 관련이 없다면 이벤트를 발생시켜야 합니다.

사용자 지정 작업의 오류 처리

작업 작성자에게 예외 처리는 조금 다른 의미가 있습니다. 작업에서 예외를 처리하는 목적에는 오류를 처리하여 가능한 경우 예외가 전달되어 워크플로가 방해받는 것을 방지하고 처리되지 않은 예외가 작업에서 전달되는 경우 올바르게 정리하는 두 가지 단계가 있습니다.

작업도 클래스이므로 작업 내에서 예외를 처리하는 것은 다른 클래스에서 처리하는 것과 다르지 않습니다. 예외를 발생시킬 수 있는 다른 구성 요소를 호출할 때는 try/catch 블록을 사용합니다. 그러나 작업에서 예외를 포착하면 예외를 다시 발생시킬지를 결정해야 합니다. 예외가 작업의 결과에 영향을 주는 것이 아니거나 작업 실패를 알릴 수 있는 더 제어하기 쉬운 방법이 작업에 있는 경우에는 이것이 이러한 피드백을 제공하는 더 나은 방법입니다. 그러나 예외가 작업이 실패했고 처리를 완료할 수 없음을 의미하거나 실패 사실을 알려 주는 경우에는 워크플로 개발자가 예외를 처리하는 비즈니스 프로세스를 디자인할 수 있도록 예외를 발생시켜야 합니다.

작업에서 예외 처리의 다른 측면은 작업 리소스 정리에 대한 것입니다. 워크플로의 오류 처리에서는 비즈니스 프로세스, 로깅 및 알림을 집중적으로 다루지만 작업의 오류 처리에서는 작업 실행에 사용된 리소스의 정리를 집중적으로 다룹니다.

리프 작업이나 복합 작업을 작성하는지 여부에 따라서도 오류를 처리하는 방법이 다릅니다. 리프 작업에서는 처리되지 않은 예외를 런타임이 포착하면 작업이 사용 중인 리소스를 해제하고 시작된 실행을 정리할 수 있도록 HandleFault 메서드가 호출됩니다. 예를 들어 작업이 실행 중에 데이터베이스를 사용하는 경우 HandleFault 메서드는 아직 끊어지지 않은 연결을 끊고 사용 중인 다른 리소스가 있으면 이를 제거해야 합니다. 작업이 시작한 비동기 동작이 있는 경우 지금이 해당 동작을 취소하여 해당 프로세싱에 사용된 리소스를 해제할 수 있는 시점입니다.

복합 작업의 경우 HandleFault 메서드가 실행된다면 작업 자체에서 논리 오류가 있거나 자식 작업이 Faulted 상태이기 때문일 수 있습니다. 두 경우 모두 복합 작업에서 HandleFault 메서드를 호출하는 의도는 작업이 해당 자식 작업을 정리하도록 허용하기 위한 것입니다. 이 정리에는 복합이 더 이상의 작업 실행을 요청하지 않는지 확인하고 실행 중인 모든 작업을 취소하는 것이 포함됩니다. 다행스럽게도 CompositeActivity 기본 클래스에 정의된 HandleFault 메서드의 기본 구현은 복합 작업의 Cancel 메서드를 호출하는 것입니다.

취소는 몇 가지 동작을 비동기적으로 시작하고 현재는 해당 동작이 완료되기를 기다리고 있는 작업이 시작한 이러한 동작을 취소하고 사용 리소스를 정리하여 종료할 수 있도록 하는 다른 메커니즘입니다. 다른 작업에서 오류가 발생한 경우 현재 작업을 취소할 수 있으며 정상적인 상황에서는 부모 복합 작업의 제어 흐름 논리에서 작업을 취소하도록 결정하는 경우 작업을 취소할 수 있습니다.

작업이 취소될 때 런타임은 해당 작업의 상태를 Canceling으로 설정하고 작업의 Cancel 메서드를 호출합니다. 예를 들어 Replicator 작업은 각각 데이터 조각을 제공하여 자식 작업의 여러 반복을 시작하고 병렬로 실행하도록 이러한 작업을 예약할 수 있습니다. 각 자식 작업이 종료될 때마다 평가되는 UntilCondition 속성도 있습니다. UntilCondition이 평가될 때 작업이 완료해야 하는지 결정하도록 할 수 있으며 실제 이러한 경우가 많습니다.

Replicator가 종료하려면 먼저 모든 자식 개체를 종료해야 합니다. 이러한 작업은 이미 예약되었으며 실행 중일 수도 있기 때문에 Replicator 작업은 ExecutionStatus 속성의 현재 값을 확인하고 값이 Executing인 경우 해당 작업을 취소하도록 런타임에 요청합니다.

보정 사용

워크플로에서 오류를 처리하면 개발자가 즉각적인 예외 상황에 대처할 수 있습니다. 또한 트랜잭션을 사용하면 작업의 범위를 지정하여 일관성을 보장할 수 있게 됩니다. 그러나 장기 실행 워크플로에서는 두 개의 작업 단위에 일관성이 필요하지만 트랜잭션을 사용할 수는 없는 경우가 있습니다.

예를 들어 워크플로가 시작되면 CRM 시스템에 고객을 추가하는 것처럼 기간 업무 응용 프로그램의 데이터를 업데이트할 수 있습니다. 이 작업은 CRM에서 워크플로의 상태와 함께 여러 작업에 거쳐 일관성을 제공하기 위한 트랜잭션의 일부일 수도 있습니다. 그리고 며칠이 될 수도 있는 기간 동안 사용자의 입력을 기다린 후에 워크플로가 고객 정보로 회계 시스템을 업데이트했을 수 있습니다. 회계 시스템과 CRM 시스템이 모두 일관성 있는 데이터를 가질 수는 있지만 이러한 리소스에 이렇게 장기간에 걸쳐 원자성 트랜잭션을 사용할 수는 없습니다. 문제는 어떻게 하면 두 번째 시스템을 업데이트할 때 발생한 예외를 처리하여 첫 번째 시스템에 이미 커밋된 변경 내용과 일관성을 유지할 수 있는가 하는 것입니다.

fig04.gif

그림 4 While 작업을 재시도 논리로 사용

두 시스템의 작업을 트랜잭션으로 일관성 있게 만들 수는 없기 때문에 두 번째 시스템을 업데이트할 때 오류를 탐지하고 첫 번째 시스템에 수행된 작업을 취소하거나 변경하여 일관성을 유지하는 메커니즘이 필요합니다. 이 변경을 탐지하고 이 프로세스를 시작하는 것은 자동으로 처리할 수 있지만 첫 번째 시스템을 수정하는 작업은 개발자가 지정해야 합니다.

WF에서는 이러한 프로세스를 보정이라고 하며 보정을 사용하는 워크플로의 개발을 지원하기 위한 몇 가지 작업이 제공됩니다. 보정 및 보정 관련 작업을 사용하는 데 대한 자세한 내용은 2007년 6월호 MSDN Magazine에서 트랜잭션 워크플로에 대한 Dino Esposito의 Cutting Edge 칼럼("트랜잭션 워크플로")을 참조하십시오.

Retry 작업

워크플로에서 예외에 대처하는 데 대한 문제 중 하나는 예외가 발생하면 이를 포착하더라도 프로세스의 다음 단계로 실행이 진행된다는 것입니다. 워크플로에 정의된 비즈니스 논리가 성공적으로 실행될 때까지 실행이 진행되지 않아야 하는 비즈니스 프로세스가 많습니다. 이러한 경우 개발자는 While 작업을 사용하여 재시도 논리를 제공하고 오류가 발생하는 한 작업이 계속 실행되도록 작업의 조건을 정의할 수 있습니다. 또한 Delay 작업을 사용하면 재시도 논리가 즉시 실행되는 것을 방지할 수 있습니다.

While 작업의 자식으로 Sequence 작업을 사용하면 이러한 재시도 모델이 가능해집니다. 또한 시퀀스의 특정한 작업 단위를 다른 시퀀스나 복합 작업에 래핑하고 모든 예외 처리기를 Fault Handlers 보기에 정의한 오류 처리 범위로 작동하여 예외를 처리하는 경우도 많습니다. 이 경우 워크플로의 상태를 수정하여 While 작업의 조건에 영향을 주는 데는 일반적으로 IfElse 작업이 사용됩니다.

예외가 발생하지 않으면 논리는 While 작업을 종료할 수 있도록 일종의 플래그 역할을 하는 속성을 설정합니다. 예외가 발생하면 While 작업이 다시 실행되도록 플래그를 설정하며 Delay 작업을 사용하여 다음 시도 전에 필요한 만큼 대기합니다. 그림 4에는 While 작업을 사용하여 워크플로에서 작업을 재시도하는 예가 나와 있습니다.

이러한 특정 패턴은 여러 시나리오에 활용이 가능하지만 재시도해야 하는 작업이 5-10개인 워크플로의 경우도 생각해 보아야 합니다. 이러한 작업을 위한 재시도 논리를 작성하기는 쉽지 않습니다. 다행스럽게도 WF는 개발자가 사용자 지정 복합 작업을 포함하여 사용자 지정 작업을 작성할 수 있도록 지원하고 있습니다. 이것은 직접 Retry 작업을 작성하여 예외가 발생할 때 자식 작업의 실행을 캡슐화할 수 있음을 의미합니다. 이 기능을 유용하게 사용할 수 있도록 하기 위해서는 재시도 간의 대기 시간 간격, 그리고 예외가 전달되어 처리되도록 하기까지 최대 재시도 횟수의 두 가지 핵심 입력을 제공해야 합니다.

이 칼럼의 나머지 부분에서는 Retry 작업의 논리에 대해 자세히 살펴보겠습니다. 사용자 지정 작업을 작성하는 데 대한 배경 정보는 필자의 이전 기사("Windows Workflow: 워크플로 범위 확장을 위한 사용자 지정 작업 만들기")를 참조하십시오. ActivityExecutionContext를 사용하여 자식 작업을 반복하는 방법에 대한 자세한 내용은 2007년 6월호의 본 칼럼("워크플로와 ActivityExecutionContext")을 참조하십시오.

자식 작업을 올바르게 관리하기 위해 중요한 것은 오류가 언제 발생하는지 알 수 있도록 작업을 모니터링할 수 있어야 한다는 것입니다. 따라서 자식 작업을 실행할 때 Retry 작업은 자식 작업이 종료될 때는 물론이고 자식 작업이 Faulting 상태가 될 때 알림을 받도록 등록합니다. 그림 5에는 자식 작업의 각 반복을 시작할 때 사용되는 BeginIteration 메서드가 나와 있습니다. 작업을 예약하기 전에 Closed와 Faulting 이벤트에는 처리기가 등록됩니다.

그림 5 자식 작업 실행 및 오류 등록

Activity child = EnabledActivities[0];
ActivityExecutionContext newContext = 
  executionContext.ExecutionContextManager.CreateExecutionContext(child);

newContext.Activity.Closed += 
  new 
EventHandler<ActivityExecutionStatusChangedEventArgs>(child_Closed);

newContext.Activity.Faulting += 
  new 
EventHandler<ActivityExecutionStatusChangedEventArgs>(Activity_Faulting);

newContext.ExecuteActivity(newContext.Activity);

자식 작업에 오류가 있으면 일반적으로 부모 작업도 Faulting 상태가 됩니다. 이러한 상황을 방지하기 위해 자식 작업에 오류가 있으면 Retry 작업은 이미 최대 횟수만큼 작업을 재시도했는지 확인합니다. 아직 재시도 횟수가 남은 경우 이 코드는 자식 작업에서 현재 예외를 무효화하여 예외를 은폐합니다.

void Activity_Faulting(object sender, 
  ActivityExecutionStatusChangedEventArgs e)
{
  e.Activity.Faulting -= Activity_Faulting;
  if(CurrentRetryAttempt < RetryCount) 
e.Activity.SetValue(
    ActivityExecutionContext.CurrentExceptionProperty, null);
}

논리에서는 자식 작업이 종료될 때 ExecutionResult 속성을 사용하여 작업이 어떻게 해서 Closed 상태가 되었는지 확인해야 합니다. 모든 작업은 최종적으로 Closed 상태가 되므로 ExecutionStatus에서는 실제 결과를 알아내는 데 필요한 정보가 없지만 ExecutionResult를 보면 작업에 오류가 있었는지, 성공했는지 또는 취소되었는지를 알 수 있습니다. 자식 작업이 성공한 경우 재시도가 필요 없으며 Retry 작업은 종료하면 됩니다.

if (e.ExecutionResult == ActivityExecutionResult.Succeeded)
{
  this.SetValue(ActivityExecutionContext.CurrentExceptionProperty, null);
  thisContext.CloseActivity();
  return;
}

종료되는 작업의 결과가 성공이 아니고 재시도 횟수가 남아 있는 경우, 재시도 시간 간격만큼 기다린 다음 작업을 다시 실행해야 합니다. 그림 6에는 다음 반복을 곧바로 시작하지 않고 작업에 구성된 간격을 사용하여 타이머 구독을 만드는 예가 나와 있습니다.

그림 6 타이머 구독 만들기

if (CurrentRetryAttempt++ < RetryCount &&
    this.ExecutionStatus == ActivityExecutionStatus.Executing) {

  this.SetValue(ActivityExecutionContext.CurrentExceptionProperty, null);

  DateTime expires = DateTime.UtcNow.Add(RetryInterval);
  SubscriptionID = Guid.NewGuid();

  WorkflowQueuingService qSvc = 
    thisContext.GetService<WorkflowQueuingService>();
  WorkflowQueue q = qSvc.CreateWorkflowQueue(SubscriptionID, false);
  q.QueueItemAvailable += new EventHandler<QueueEventArgs>(TimerExpired);

  TimerEventSubscription subscription = new TimerEventSubscription(
    SubscriptionID, WorkflowInstanceId, expires);
  TimerEventSubscriptionCollection timers = 
    GetTimerSubscriptionCollection();
  timers.Add(subscription);

  return;
}

타이머가 만료되면 다음과 같이 TimerExpired 메서드가 호출됩니다.

void TimerExpired(object sender, QueueEventArgs e)
{
  ActivityExecutionContext ctx = 
    sender as ActivityExecutionContext;
  CleanupSubscription(ctx);
  BeginIteration(ctx);
}

fig07.gif

그림 7 워크플로의 Retry 작업

이렇게 하면 자식 작업의 다음 반복이 시작됩니다. 작업은 TimerEventSubscription 클래스를 사용하여 워크플로의 타이머 컬렉션에 타이머를 추가함으로써 런타임에 현재 구성되어 있는 지속성 서비스에 관계없이 지속성 및 재개에 참여할 수 있게 됩니다. 재시도 간격이 길면 타이머가 만료될 때까지 전체 워크플로에 메모리가 부족해질 수 있습니다.

이제 워크플로 작업의 핵심 동작 요구 사항이 충족되었습니다. 자식 작업에서 오류가 발생하더라도 Retry 작업에서는 오류가 발생하지 않으며 재시도 시간 간격만큼 대기한 후에 자식 작업을 다시 실행합니다.

마지막으로 처리할 단계는 재시도 횟수만큼 작업을 시도했지만 자식 개체가 계속 실패하는 경우입니다. 이 경우에는 작업에서 정상적으로 오류가 발생하도록 하는 것이 목표이므로 Activity_Faulting 메서드는 자식 작업에서 예외를 제거하지 않습니다. 그리고 자식 작업이 종료되면 Retry 작업도 함께 종료됩니다.

모든 재시도가 실패한 후에 Retry가 종료되면 결과는 시퀀스에서 원래 작업에 오류가 발생한 것과 동일합니다. Retry 작업에도 FaultHandler 작업을 정의할 수 있으며 이러한 오류 처리기는 재시도가 모두 실행된 후에 실행됩니다. 이 모델을 사용하면 재시도가 필요할 수도 있는 작업이 포함된 워크플로의 개발을 간소화하면서도 그림 7에 나오는 것처럼 오류 처리와 관련된 워크플로 개발자의 개발 환경을 동일하게 유지할 수 있습니다.

또한 재시도가 실패하면 자식 작업에 대한 오류 처리기가 실행되므로 워크플로 개발자는 어떤 작업에서 오류를 처리할지 선택할 수 있습니다. 자식 작업에서는 작업이 실패할 때마다 각 반복에서 정리할 기회를 갖도록 HandleFault 메서드가 호출됩니다.

질문이나 의견이 있으면 mmnet30@microsoft.com으로 보내시기 바랍니다.

Matt Milner는 Pluralsight의 기술 담당자 중 한 명으로 연결된 시스템 기술을 전문적으로 담당하고 있습니다. Matt는 Windows Workflow Foundation, BizTalk Server, ASP.NET 및 Windows Communication Foundation 등의 Microsoft .NET 기술을 전문으로 다루는 독립 컨설턴트이기도 합니다. Matt는 아내인 Kristen, 그리고 두 아들과 함께 미국 미네소타 주에 거주하고 있습니다. 그의 블로그(pluralsight.com/community/blogs/matt)를 통해 Matt를 만나 보십시오.