

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 워크플로 구현
<a name="workflowimpl"></a>

워크플로를 구현하려면 원하는 `@Workflow` 인터페이스를 구현하는 클래스를 작성합니다. 인스턴스의 경우 예시 워크플로 인터페이스(`MyWorkflow`)는 다음과 같이 구현될 수 있습니다.

```
public class MyWFImpl implements MyWorkflow
{
  MyActivitiesClient client = new MyActivitiesClientImpl();
  @Override
  public void startMyWF(int a, String b){
    Promise<Integer> result = client.activity1();
    client.activity2(result);
  }
  @Override
  public void signal1(int a, int b, String c){
    //Process signal
     client.activity2(a + b);
  }
}
```

이 클래스의 `@Execute` 메서드는 워크플로 로직의 진입점입니다. 프레임워크는 결정 작업을 처리할 때 재생을 사용하여 객체 상태를 재구성하므로 각 결정 작업에 대해 새 객체가 생성됩니다.

`Promise<T>`를 파라미터로 사용하는 것은 `@Workflow` 인터페이스 내 `@Execute` 메서드에서 허용되지 않습니다. 이는 비동기식 호출이 순전히 호출자의 결정이기 때문입니다. 워크플로 구현 자체는 호출이 동기식이었는지 비동기식이었는지 여부에 의존하지 않습니다. 따라서 생성된 클라이언트 인터페이스에는 이 메서드가 비동기식으로 호출될 수 있도록 `Promise<T>` 파라미터를 받아들이는 오버로드가 있습니다.

`@Execute` 메서드의 반환 유형은 `void` 또는 `Promise<T>`만 가능합니다. 해당하는 외부 클라이언트의 반환 유형은 `Promise<>`가 아닌 `void`임에 유의하십시오. 외부 클라이언트는 비동기 코드에서 사용하기 위한 것이 아니므로 `Promise` 객체를 반환하지 않습니다. 외부로 표시된 워크플로 실행의 결과를 얻으려면 워크플로가 활동을 통해 외부 데이터 스토어에서 상태를 업데이트하도록 설계할 수 있습니다. 또한 Amazon SWF의 시각화 API는 진단 목적으로 워크플로의 결과를 가져오는 데 사용할 수 있습니다. 가시성 APIs를 사용하여 워크플로 실행 결과를 일반적으로 검색하는 것은 권장되지 않습니다. 이러한 API 호출은 Amazon SWF에 의해 제한될 수 있기 때문입니다. 시각화 API를 사용하려면 `WorkflowExecution` 구조를 사용하는 워크플로 실행을 식별해야 합니다. 이 구조는 생성된 워크플로 클라이언트에서 `getWorkflowExecution` 메서드를 호출하여 얻을 수 있습니다. 그러면 이 메서드에서는 클라이언트가 묶인 워크플로 실행에 상응하는 `WorkflowExecution` 구조를 반환합니다. 시각화 API에 대한 자세한 내용은 [Amazon Simple Workflow Service API 참조](https://docs.aws.amazon.com/amazonswf/latest/apireference/)를 참조하십시오.

워크플로 구현에서 활동을 호출할 때는 생성된 활동 클라이언트를 사용해야 합니다. 이와 마찬가지로 신호를 전송하려면 생성된 워크플로 클라이언트를 사용합니다.

## 결정 컨텍스트
<a name="workflowimpl.decisioncontext"></a>

프레임워크에서는 워크플로 코드가 프레임워크에서 실행될 때마다 주변 컨텍스트를 제공합니다. 이 컨텍스트에서는 타이머 생성과 같은 워크플로 구현에서 액세스할 수 있는 컨텍스트 고유 기능을 제공합니다. 자세한 내용은 [실행 콘텍스트](executioncontext.md) 단원을 참조하십시오.

## 실행 상태 노출
<a name="workflowimpl.executionstate"></a>

Amazon SWF를 통해 사용자는 워크플로 내역에서 사용자 지정 상태를 추가할 수 있습니다. 워크플로 실행에서 보고하는 최신 상태는 Amazon SWF 서비스에 대한 시각화 호출을 통해 Amazon SWF 콘솔에서 사용자에게 반환됩니다. 예를 들어 주문 처리 워크플로에서는 '주문 접수', '주문 배송' 등 여러 단계에서 주문 상태를 보고할 수 있습니다. AWS Flow Framework for Java에서는 이 작업이 `@GetState` 주석이 붙은 워크플로 인터페이스에서 메서드를 통해 수행됩니다. 결정자는 결정 작업 처리를 마치면 이 메서드를 호출하여 워크플로 구현에서 최신 상태를 조회합니다. 상태는 시각화 호출 외에도 생성된 외부 클라이언트(내부적으로는 시각화 API를 사용함)를 사용하여 조회할 수 있습니다.

다음 예시에서는 실행 컨텍스트를 설정하는 방법을 보여줍니다.

```
@Workflow
@WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 60,
               defaultTaskStartToCloseTimeoutSeconds = 10)
public interface PeriodicWorkflow {

    @Execute(version = "1.0")
    void periodicWorkflow();

    @GetState
    String getState();
}

@Activities(version = "1.0")
@ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300,
                             defaultTaskStartToCloseTimeoutSeconds = 3600)
public interface PeriodicActivity {
    void activity1();

}

public class PeriodicWorkflowImpl implements PeriodicWorkflow {

    private DecisionContextProvider contextProvider
               = new DecisionContextProviderImpl();

    private WorkflowClock clock
               = contextProvider.getDecisionContext().getWorkflowClock();

    private PeriodicActivityClient activityClient
               = new PeriodicActivityClientImpl();

    private String state;

    @Override
    public void periodicWorkflow() {
        state = "Just Started";
        callPeriodicActivity(0);
    }

    @Asynchronous
    private void callPeriodicActivity(int count,
                                      Promise<?>... waitFor)
    {
        if(count == 100) {
            state = "Finished Processing";
            return;
        }

        // call activity
        activityClient.activity1();

        // Repeat the activity after 1 hour.
        Promise<Void> timer = clock.createTimer(3600);
        state = "Waiting for timer to fire. Count = "+count;
        callPeriodicActivity(count+1, timer);
    }

    @Override
    public String getState() {
        return state;
    }
}

public class PeriodicActivityImpl implements PeriodicActivity
{
@Override
      public static void activity1()
   {
      ...
    }
}
```

생성된 외부 클라이언트는 언제든지 워크플로 실행의 최신 상태를 조회하는 데 사용할 수 있습니다.

```
PeriodicWorkflowClientExternal client
        = new PeriodicWorkflowClientExternalFactoryImpl().getClient();
System.out.println(client.getState());
```

위 예시에서 실행 상태는 여러 단계에서 보고됩니다. 워크플로 인스턴스가 시작되면 `periodicWorkflow`에서는 초기 상태를 '방금 시작됨'으로 보고합니다. 그다음에는 `callPeriodicActivity`에 대한 각 호출을 통해 워크플로 상태를 업데이트합니다. `activity1`이 100번 호출되었다면 메서드가 반환하고 워크플로 인스턴스가 완료됩니다.

## 워크플로 로컬
<a name="workflowimpl.workflowlocals"></a>

때로 워크플로 구현에서 정적 변수를 사용해야 하는 경우가 있을 수 있습니다. 예를 들어 워크플로 구현의 여러 위치(여러 클래스일 수 있음)에서 액세스해야 하는 카운터를 저장하고 싶을 수 있습니다. 하지만 정적 변수가 스레드 전체에 공유되므로 워크플로에서 정적 변수에 의존할 수는 없습니다. 작업자가 다른 스레드에 있는 다른 결정 작업을 동시에 처리할 수 있기 때문에 이것은 문제가 됩니다. 또는 워크플로 구현에서 필드에 그러한 상태를 저장할 수 있지만, 이때 구현 객체를 두루 전달해야 합니다. 이러한 필요에 대처하기 위해 프레임워크에서는 `WorkflowExecutionLocal<?>` 클래스를 제공합니다. 의미론과 같은 정적 변수가 있어야 하는 모든 상태는 `WorkflowExecutionLocal<?>`을 사용하는 인스턴스 로컬로 보관되어야 합니다. 사용자는 이 유형의 정적 변수를 선언하고 사용할 수 있습니다. 예를 들어 다음 코드 조각에서 `WorkflowExecutionLocal<String>`은 사용자 이름을 저장하는 데 사용됩니다.

```
public class MyWFImpl implements MyWF {
  public static WorkflowExecutionLocal<String> username
      = new WorkflowExecutionLocal<String>();

  @Override
  public void start(String username){
    this.username.set(username);
    Processor p = new Processor();
    p.updateLastLogin();
    p.greetUser();
   }

  public static WorkflowExecutionLocal<String> getUsername() {
    return username;
  }

  public static void setUsername(WorkflowExecutionLocal<String> username) {
    MyWFImpl.username = username;
  }
}

public class Processor {
  void updateLastLogin(){
    UserActivitiesClient c = new UserActivitiesClientImpl();
    c.refreshLastLogin(MyWFImpl.getUsername().get());
  }
   void greetUser(){
    GreetingActivitiesClient c = new GreetingActivitiesClientImpl();
    c.greetUser(MyWFImpl.getUsername().get());
  }
}
```