

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 执行关联
<a name="executioncontext"></a>

**Topics**
+ [决策上下文](#executioncontext.decision)
+ [活动执行上下文](#activitycontext)

该框架为工作流程和活动实现提供环境上下文。该上下文是处理的任务特有的，并提供一些可在您的实现中使用的实用工具。每次工作线程处理新任务时，将会创建一个上下文对象。

## 决策上下文
<a name="executioncontext.decision"></a>

在执行决策任务时，该框架通过 `DecisionContext` 类为工作流程实现提供上下文。`DecisionContext` 提供上下文敏感信息，如工作流程执行运行 ID 以及时钟和计时器功能。

### DecisionContext 在工作流程实现中访问
<a name="executioncontext.decision.access"></a>

您可以使用 `DecisionContextProviderImpl` 类在您的工作流程实现中访问 `DecisionContext`。或者，您也可以使用 Spring 在您的工作流程实现的字段或属性中注入上下文，如“可测性和依赖关系注入”一节中所示。

```
DecisionContextProvider contextProvider
    = new DecisionContextProviderImpl();
DecisionContext context = contextProvider.getDecisionContext();
```

### 创建时钟和计时器
<a name="executioncontext.decision.timer"></a>

`DecisionContext` 包含一个 `WorkflowClock` 类型的属性，它提供计时器和时钟功能。由于工作流程逻辑必须是确定性的，因此不应在工作流程实现中直接使用系统时钟。`WorkflowClock` 上的 `currentTimeMills` 方法返回处理的决策的启动事件的时间。这可确保在重播期间获得相同的时间值，从而使您的工作流程逻辑具有确定性。

`WorkflowClock` 还具有一个返回 `Promise` 对象的 `createTimer` 方法，该对象在指定的间隔后变为就绪状态。您可以将该值作为其他异步方法的参数，以将其执行推迟指定的一段时间。这样，您实际上可以将异步方法或活动安排在以后的时间执行。

以下列表中的示例说明了如何定期调用活动。

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

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

@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();

    @Override
    public void periodicWorkflow() {
        callPeriodicActivity(0);
    }

    @Asynchronous
    private void callPeriodicActivity(int count,
                                      Promise<?>... waitFor) {
        if (count == 100) {
            return;
        }
        PeriodicActivityClient client = new PeriodicActivityClientImpl();
        // call activity
        Promise<Void> activityCompletion = client.activity1();

        Promise<Void> timer = clock.createTimer(3600);

        // Repeat the activity either after 1 hour or after previous activity run
        // if it takes longer than 1 hour
        callPeriodicActivity(count + 1, timer, activityCompletion);
    }
}


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

在上述列表中，`callPeriodicActivity` 异步方法调用 `activity1`，然后使用当前 `AsyncDecisionContext` 创建一个计时器。它将返回的 `Promise` 作为参数传递到对其自身的递归调用。该递归调用等到计时器触发 (本示例中为 1 小时)，然后再执行。

## 活动执行上下文
<a name="activitycontext"></a>

就像 `DecisionContext` 在处理决策任务时提供上下文信息一样，`ActivityExecutionContext` 在处理活动任务时提供类似的上下文信息。将通过 `ActivityExecutionContextProviderImpl` 类为您的活动代码提供该上下文。

```
ActivityExecutionContextProvider provider
    = new ActivityExecutionContextProviderImpl();
ActivityExecutionContext aec = provider.getActivityExecutionContext();
```

通过使用 `ActivityExecutionContext`，您可以执行以下操作：

### 为长时间运行的活动提供检测信号
<a name="activitycontext.heartbeat"></a>

如果活动长期运行，则必须定期向 Amazon SWF 报告进度，让它知道任务仍在进行中。如果没有此类检测信号，并且在注册活动类型或计划活动时设置了任务检测信号超时，则任务可能会超时。要发送检测信号，您可以在 `recordActivityHeartbeat` 上使用 `ActivityExecutionContext` 方法。检测信号还提供了一个机制以取消正在执行的活动。有关更多详细信息和示例，请参阅[错误处理](errorhandling.md)一节。

### 获取活动任务详细信息
<a name="activitycontext.details"></a>

如果需要，您可以获取 Amazon SWF 在执行程序获取任务时传递的所有活动任务详细信息。这包括有关任务输入、任务类型和任务令牌等的信息。如果要实施手动完成的活动（例如，通过人工操作完成），则必须使用 `ActivityExecutionContext` 来检索任务令牌，并将其传递给最终完成活动任务的流程。有关更多详细信息，请参阅有关[手动完成活动](activityimpl.md#activityimpl.complete)的一节。

### 获取执行程序使用的 Amazon SWF 客户端对象
<a name="activitycontext.client"></a>

执行程序使用的 Amazon SWF 客户端对象可以通过调用 `ActivityExecutionContext` 上的 `getService` 方法来获取。如果您想直接调用 Amazon SWF 服务，这会非常有用。