

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

# HelloWorldWorkflowAsync 애플리케이션
<a name="getting-started-example-helloworldworkflowasync"></a>

어떤 경우에는 활동을 사용하는 대신에 워크플로에서 특정 작업을 로컬로 수행하도록 하는 것이 더 좋습니다. 그러나 워크플로 작업에는 `Promise<T>` 객체에서 표시하는 값을 처리하는 과정이 수반되는 경우가 많습니다. `Promise<T>` 객체를 동기식 워크플로 메서드에 전달하면 이 메서드가 즉시 실행되지만 객체가 준비 상태가 될 때까지는 `Promise<T>` 객체의 값에 액세스할 수 없습니다. `Promise<T>.isReady`는 `true`를 반환할 때까지 폴링할 수 있지만, 이렇게 하는 것은 비능률적이므로 메서드가 장시간 차단할 수 있습니다. 더 좋은 방법은 *비동기식 메서드*를 사용하는 것입니다.

비동기 메서드는 표준 메서드(워크플로 구현 클래스의 멤버로 사용)와 매우 유사하게 구현되며 워크플로 구현 컨텍스트에서 실행됩니다. 사용자는 `@Asynchronous` 주석을 적용하여 워크플로 구현을 비동기식 메서드로 지정합니다. 이를 통해 프레임워크에게 워크플로 구현을 활동과 흡사하게 취급하도록 지시합니다.
+ 워크플로 구현에서 비동기식 메서드를 호출하면 비동기식 메서드에서 즉시 반환합니다. 비동기식 메서드에서는 일반적으로 이 메서드가 완료될 때 준비 상태가 되는 `Promise<T>` 객체를 반환합니다.
+ 비동기식 메서드에 `Promise<T>` 객체를 한 개 이상 전달하면 이 메서드는 모든 입력 객체가 준비 상태가 될 때까지 실행을 연기합니다. 따라서 비동기식 메서드에서는 입력 `Promise<T>` 값에 액세스할 때 예외가 반환될 위험이 없습니다.

**참고**  
 AWS Flow Framework for Java가 워크플로를 실행하는 방식 때문에 비동기식 메서드는 일반적으로 여러 번 실행되므로 빠른 간접비 작업에만 사용해야 합니다. 활동은 대규모 컴퓨팅과 같이 시간이 오래 걸리는 작업을 수행할 때 사용해야 합니다. 자세한 내용은 [AWS Flow Framework 기본 개념: 분산 실행](awsflow-basics-distributed-execution.md)을 참조하세요.

이 주제에서는 활동 중 하나를 비동기식 메서드로 대치하는 HelloWorldWorkflow의 수정 버전인 HelloWorldWorkflowAsync를 연습합니다. 애플리케이션을 구현하려면 프로젝트 디렉터리에 helloWorld.HelloWorldWorkflow 패키지의 사본을 생성하고 이 사본의 이름을 helloWorld.HelloWorldWorkflowAsync로 지정합니다.

**참고**  
이 주제는 [HelloWorld 애플리케이션](getting-started-example-helloworld.md) 및 [HelloWorldWorkflow 애플리케이션](getting-started-example-helloworldworkflow.md) 주제에 있는 개념과 파일을 기반으로 합니다. 계속하기 전에 그러한 주제에 있는 파일과 개념을 익히십시오.

다음 단원에서는 비동기식 메서드를 사용하기 위해 원본 HelloWorldWorkflow 코드를 수정하는 방법을 설명합니다.

## HelloWorldWorkflowAsync 활동 구현
<a name="getting-started-example-helloworldworkflowasync.activities"></a>

HelloWorldWorkflowAsync에서는 다음과 같이 `GreeterActivities`에 활동 작업자 인터페이스를 구현합니다.

```
import com.amazonaws.services.simpleworkflow.flow.annotations.Activities;
import com.amazonaws.services.simpleworkflow.flow.annotations.ActivityRegistrationOptions;

@Activities(version="2.0")
@ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300,
                             defaultTaskStartToCloseTimeoutSeconds = 10)
public interface GreeterActivities {
   public String getName();
   public void say(String what);
}
```

이 인터페이스는 다음 사항을 제외하면 HelloWorldWorkflow에서 사용하는 것과 비슷합니다.
+ `getGreeting` 활동을 생략합니다. 이 작업은 현재 비동기식 메서드에서 처리합니다.
+ 버전 번호가 2.0으로 설정됩니다. Amazon SWF에 활동 인터페이스를 등록한 후에는 버전 번호를 바꾸지 않는 한 수정할 수 없습니다.

나머지 활동 메서드 구현은 HelloWorldWorkflow와 동일합니다. `GreeterActivitiesImpl`에서 `getGreeting`만 삭제합니다.

## HelloWorldWorkflowAsync 워크플로 구현
<a name="getting-started-example-helloworldworkflowasync.workflow"></a>

HelloWorldWorkflowAsync에서는 워크플로 인터페이스를 다음과 같이 정의합니다.

```
import com.amazonaws.services.simpleworkflow.flow.annotations.Execute;
import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow;
import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions;

@Workflow
@WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 3600)
public interface GreeterWorkflow {

   @Execute(version = "2.0")
   public void greet();
}
```

이 인터페이스는 새 버전 번호 외에는 HelloWorldWorkflow와 동일합니다. 활동과 마찬가지로 등록된 워크플로를 변경하고 싶다면 버전을 변경해야 합니다.

HelloWorldWorkflowAsync에서는 워크플로를 다음과 같이 구현합니다.

```
import com.amazonaws.services.simpleworkflow.flow.annotations.Asynchronous;
import com.amazonaws.services.simpleworkflow.flow.core.Promise;

public class GreeterWorkflowImpl implements GreeterWorkflow {
   private GreeterActivitiesClient operations = new GreeterActivitiesClientImpl();

   @Override
   public void greet() {
      Promise<String> name = operations.getName();
      Promise<String> greeting = getGreeting(name);
      operations.say(greeting);
   }

   @Asynchronous
   private Promise<String> getGreeting(Promise<String> name) {
      String returnString = "Hello " + name.get() + "!";
      return Promise.asPromise(returnString);
   }
}
```

HelloWorldWorkflowAsync에서는 `getGreeting` 활동을 `getGreeting` 비동기식 메서드로 대치하지만 `greet` 메서드는 다음과 같이 거의 같은 방식으로 작동합니다.

1. `getName` 활동을 실행하면 이름을 표시하는 `Promise<String>` 객체 `name`이 즉시 반환됩니다.

1. `getGreeting` 비동기식 메서드를 호출한 후 이 메서드에 `name` 객체를 전달합니다. `getGreeting`에서는 인사를 표시하는 `Promise<String>` 객체 `greeting`을 즉시 반환합니다.

1. `say` 활동을 실행한 후 이 활동에 `greeting` 객체를 전달합니다.

1. `getName`이 완료되면 `name`이 준비 상태가 되고 `getGreeting`에서는 자체 값을 사용해 인사를 구성합니다.

1. `getGreeting`이 완료되면 `greeting`이 준비 상태가 되고 `say`에서는 콘솔에 문자열을 출력합니다.

차이점은 인사에서 활동 클라이언트를 호출하여 `getGreeting` 활동을 실행하는 대신에 비동기식 `getGreeting` 메서드를 호출한다는 것입니다. 결과는 동일하지만, `getGreeting` 메서드는 `getGreeting` 활동과는 약간 다르게 작동합니다.
+ 워크플로 작업자에서는 표준 함수 호출 의미론을 사용하여 `getGreeting`을 실행합니다. 그러나 활동의 비동기식 실행은 Amazon SWF에서 조정합니다.
+ `getGreeting`은 워크플로 구현 프로세스 중에 실행됩니다.
+ `getGreeting`에서는 `String` 객체가 아닌 `Promise<String>` 객체를 반환합니다. `Promise`이 보유한 문자열 값을 얻으려면 `get()` 메서드를 호출해야 합니다. 그러나 활동이 비동기식으로 실행되므로 반환 값이 즉시 준비되지 않을 수 있습니다. `get()`는 비동기식 메서드의 반환 값을 사용할 수 있을 때까지 예외를 발생시킵니다.

  `Promise` 작동 방식에 대한 자세한 내용은 [AWS Flow Framework 기본 개념: 활동과 워크플로 간의 데이터 교환](awsflow-basics-data-exchange-activities-workflows.md) 단원을 참조하십시오.

`getGreeting`에서는 정적 `Promise.asPromise` 메서드에 인사 문자열을 전달하여 반환 값을 생성합니다. 이 메서드에서는 적절한 유형의 `Promise<T>` 객체를 생성한 후 값을 설정하여 이 값을 준비 상태에 입력합니다.

## HelloWorldWorkflowAsync 워크플로 및 활동 호스트와 시작자
<a name="getting-started-example-helloworldworkflowasync.host"></a>

HelloWorldWorkflowAsync에서는 `GreeterWorker`를 워크플로 및 활동 구현에 대해 호스트 클래스로 구현합니다. 이것은 "`HelloWorldAsyncList`"로 설정된 `taskListToPoll` 이름 외에는 HelloWorldWorkflow 구현과 동일합니다.

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;
import com.amazonaws.services.simpleworkflow.flow.ActivityWorker;
import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker;

public class GreeterWorker {
    public static void main(String[] args) throws Exception {
        ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000);

        String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID");
        String swfSecretKey = System.getenv("AWS_SECRET_KEY");
        AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey);

        AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config);
        service.setEndpoint("https://swf.us-east-1.amazonaws.com");

        String domain = "helloWorldWalkthrough";
        String taskListToPoll = "HelloWorldAsyncList";

        ActivityWorker aw = new ActivityWorker(service, domain, taskListToPoll);
        aw.addActivitiesImplementation(new GreeterActivitiesImpl());
        aw.start();

        WorkflowWorker wfw = new WorkflowWorker(service, domain, taskListToPoll);
        wfw.addWorkflowImplementationType(GreeterWorkflowImpl.class);
        wfw.start();
    }
}
```

HelloWorldWorkflowAsync에서는`GreeterMain`에 워크플로 시작자를 구현하는데, 이것은 HelloWorldWorkflow 구현과 동일합니다.

워크플로를 실행하려면 HelloWorldWorkflow와 마찬가지로 `GreeterWorker` 및 `GreeterMain`를 실행하십시오.