

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# AWS Flow Framework per la guida alla programmazione Java
<a name="features"></a>

Questa sezione fornisce dettagli su come utilizzare le funzionalità di AWS Flow Framework for Java per implementare applicazioni di flusso di lavoro.

**Topics**
+ [Implementazione di applicazioni di workflow con AWS Flow Framework](awsflow-developing-workflows.md)
+ [Contratti di flusso di lavoro e attività](features.workflow.md)
+ [Registrazione dei tipi di flusso di lavoro e di attività](features.registration.md)
+ [Client di attività e flusso di lavoro](clients.md)
+ [Implementazione del flusso di lavoro](workflowimpl.md)
+ [Implementazione di attività](activityimpl.md)
+ [AWS Lambda Attività di implementazione](lambda-task.md)
+ [Esecuzione di programmi scritti con AWS Flow Framework for Java](running.md)
+ [Contesto di esecuzione](executioncontext.md)
+ [Esecuzioni del flusso di lavoro figlio](childworkflow.md)
+ [Flussi di lavoro continui](continuous.md)
+ [Impostazione della priorità delle attività in Amazon SWF](programming-priority.md)
+ [DataConverters](dataconverters.md)
+ [Passaggio di dati a metodi asincroni](advanceddatapassing.md)
+ [Testabilità e inserimento delle dipendenze](test.md)
+ [Gestione errori](errorhandling.md)
+ [Ripetere le attività non andate a buon fine](features-retry.md)
+ [Task Daemon](daemontasks.md)
+ [AWS Flow Framework per Java Replay Behavior](programming-replay.md)

# Implementazione di applicazioni di workflow con AWS Flow Framework
<a name="awsflow-developing-workflows"></a>

I passaggi tipici necessari per lo sviluppo di un flusso di lavoro con AWS Flow Framework sono:

1. **Definizione dei contratti di attività e flusso di lavoro**. Analizza i requisiti della tua applicazione, quindi determina le attività e la topologia di flusso di lavoro necessarie. Le *attività* gestiscono i task di elaborazione richiesti mentre la *topologia di flusso di lavoro* definisce la logica di business e la struttura di base del flusso di lavoro.

   Ad esempio, è possibile che per un'applicazione di elaborazione di contenuti multimediali sia necessario scaricare ed elaborare un file e quindi caricarlo in un bucket Amazon Simple Storage Service (S3). Questa procedura potrebbe essere suddivisa in quattro task di attività:

   1. Download del file da un server

   1. Elaborazione del file (ad esempio, transcodificandolo in un formato multimediale differente)

   1. Caricamento del file nel bucket S3

   1. Pulizia con eliminazione dei file locali

   Questo flusso di lavoro avrebbe un metodo del punto di ingresso e implementerebbe una topologia lineare semplice che esegue le attività in sequenza, come l'[HelloWorldWorkflow Applicazione](getting-started-example-helloworldworkflow.md).

1. **Implementazione delle interfacce di attività e flusso di lavoro**. I contratti di flusso di lavoro e attività sono definiti dalle *interfacce* Java, rendendo le relative convenzioni di chiamata previsibili con SWF e fornendo flessibilità nell'implementazione della logica di flusso di lavoro e dei task di attività. Le differenti parti del programma possono agire da consumer dei dati delle altre parti, ma non devono essere necessariamente a conoscenza dei dettagli di implementazione delle altre parti.

   Ad esempio, puoi definire un'interfaccia `FileProcessingWorkflow` e fornire differenti implementazioni di flusso di lavoro per codifica di video, compressione, anteprime e così via. Ognuno di questi flussi di lavoro può avere differenti flussi di controllo nonché chiamare differenti metodi di attività e non è necessario che lo starter di flusso di lavoro ne sia a conoscenza. Grazie alle interfacce, risulta semplice anche testare i flussi di lavoro utilizzando implementazioni fittizie che possono essere sostituite in seguito con codice funzionale.

1. **Generazione di client di attività e flusso di lavoro**. AWS Flow Framework Elimina la necessità di implementare i dettagli relativi alla gestione dell'esecuzione asincrona, all'invio di richieste HTTP, allo smistamento dei dati e così via. In effetti, lo starter di flusso di lavoro esegue un'istanza di flusso di lavoro chiamando un metodo sul client di flusso di lavoro e l'implementazione di flusso di lavoro esegue le attività chiamando metodi sul client di attività. Il framework gestisce i dettagli di queste interazioni in background.

   Se utilizzi Eclipse e hai configurato il tuo progetto, ad esempio, il processore di AWS Flow Framework annotazioni utilizza le definizioni dell'interfaccia per generare automaticamente client di flusso di lavoro e attività che espongono lo stesso set di metodi dell'interfaccia corrispondente. [Configurazione di AWS Flow Framework per Java](setup.md)

1. **Implementazione delle applicazioni host di attività e flusso di lavoro**. Le implementazioni del flusso di lavoro e delle attività devono essere incorporate in applicazioni host che eseguono il polling di Amazon SWF per le attività, gestiscono tutti i dati e utilizzano i metodi di implementazione appropriati. AWS Flow Framework for Java include [ActivityWorker](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/ActivityWorker.html)classi che semplificano [WorkflowWorker](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/WorkflowWorker.html)e semplificano l'implementazione delle applicazioni host.

1. **Metti alla prova il tuo flusso di lavoro.** AWS Flow Framework per Java offre un' JUnit integrazione che puoi utilizzare per testare i flussi di lavoro in linea e localmente.

1.  **Distribuzione dei lavoratori**. Puoi distribuire i tuoi lavoratori in modo appropriato, ad esempio su istanze EC2 Amazon o sui computer del tuo data center. Una volta implementate e avviate, i lavoratori iniziano a interrogare Amazon SWF per le attività e le gestiscono secondo necessità. 

1.  **Avvio delle esecuzioni**. Un'applicazione avvia un'istanza di flusso di lavoro utilizzando il client di flusso di lavoro per chiamare il punto di ingresso del flusso di lavoro. Puoi anche avviare flussi di lavoro utilizzando la console Amazon SWF. Indipendentemente da come avvii un'istanza di flusso di lavoro, puoi utilizzare la console Amazon SWF per monitorare l'istanza del flusso di lavoro in esecuzione ed esaminare la cronologia del flusso di lavoro per le istanze in esecuzione, completate e non riuscite. 

[AWS SDK per Java](https://aws.amazon.com/sdkforjava/)Include un set AWS Flow Framework di esempi Java che puoi sfogliare ed eseguire seguendo le istruzioni nel file readme.html nella directory principale. È inoltre disponibile una serie di ricette, semplici applicazioni, che mostrano come gestire una serie di problemi di programmazione specifici, disponibili su [AWS Flow Framework Recipes](https://aws.amazon.com/code/2535278400103493).

# Contratti di flusso di lavoro e attività
<a name="features.workflow"></a>

Le interfacce Java sono utilizzate per dichiarare le firme dei flussi di lavoro e delle attività. L'interfaccia forma il contratto tra l'implementazione di flusso di lavoro (o attività) e il client del flusso di lavoro (o attività). Ad esempio, un tipo di flusso di lavoro `MyWorkflow` è definito usando un'interfaccia che è annotata con l'annotazione `@Workflow`: 

```
@Workflow
@WorkflowRegistrationOptions(
   defaultExecutionStartToCloseTimeoutSeconds = 60,
   defaultTaskStartToCloseTimeoutSeconds = 10)
public interface MyWorkflow
{
    @Execute(version = "1.0")
    void startMyWF(int a, String b);

    @Signal
    void signal1(int a, int b, String c);

    @GetState
    MyWorkflowState getState();
}
```

Il contratto non dispone di impostazioni specifiche per l'implementazione. Questo utilizzo dei contratti neutrali rispetto alle implementazioni permette ai client di essere dissociati dall'implementazione e quindi offre la flessibilità per modificare i dettagli dell'implementazione senza spezzare il client. Viceversa, potresti cambiare il client senza dover modificare il flusso di lavoro o l'attività. Ad esempio, il client può essere modificato per chiamare un'attività in modo asincrono utilizzando le promesse (`Promise<T>`) senza richiedere una modifica all'implementazione di attività. Allo stesso modo, l'implementazione dell'attività può essere modificata in modo da essere completata in modo asincrono, ad esempio da una persona che invia un'e-mail, senza richiedere la modifica dei client dell'attività. 

Nell'esempio riportato sopra, l'interfaccia di flusso di lavoro `MyWorkflow` contiene un metodo, `startMyWF`, per avviare una nuova esecuzione. Questo metodo è annotato con l'annotazione `@Execute` e deve avere un tipo restituito `void` o `Promise<>`. In un'interfaccia di flusso di lavoro data, può al massimo essere annotato un metodo con questa annotazione. Questo metodo è il punto di ingresso della logica di flusso di lavoro e il framework chiama questo metodo per eseguire la logica di flusso di lavoro quando viene ricevuto un task di decisione. 

L'interfaccia di flusso di lavoro definisce inoltre i segnali che possono essere inviati al flusso di lavoro. Il metodo di segnale viene invocato quando un segnale con un nome corrispondente viene ricevuto dall'esecuzione del flusso di lavoro. Ad esempio, l'interfaccia `MyWorkflow` dichiara un metodo di segnale `signal1`, annotato con l'annotazione `@Signal`. 

L'annotazione `@Signal` è richiesta sui metodi di segnale. Il tipo restituito del metodo di segnale deve essere `void`. Un'interfaccia di flusso di lavoro potrebbe avere zero o più metodi di segnali definiti al proprio interno. Potresti dichiarare un'interfaccia di flusso di lavoro senza un metodo `@Execute` e alcuni metodi `@Signal` per generare client che non possono avviare la propria esecuzione ma inviare segnali per effettuare le esecuzioni.

Metodi annotati con le annotazioni `@Execute` e `@Signal` possono avere numeri di parametri di ogni tipo eccetto `Promise<T>` o le sue derivate. Questa funzionalità ti permette di passare input fortemente tipizzati a un'esecuzione di flusso di lavoro dall'avvio e durante la sua esecuzione. Il tipo restituito del metodo `@Execute` deve essere `void` o `Promise<>`. 

Inoltre, puoi anche dichiarare un metodo nell'interfaccia di flusso di lavoro per segnalare l'ultimo stato dell'esecuzione del flusso di lavoro, ad esempio il metodo `getState` nel precedente esempio. Questo stato non è l'intero stato di applicazione del flusso di lavoro. Lo scopo di questa funzionalità è permetterti di archiviare fino a 32 KB di data per indicare l'ultimo stato dell'esecuzione. Ad esempio, in un flusso di lavoro di elaborazione dell'ordine, potresti archiviare una stringa che indica che l'ordine è stato ricevuto, elaborato o annullato. Questo metodo viene chiamato dal framework ogni volta che un task di decisione viene completato per ottenere l'ultimo stato. Lo stato è memorizzato in Amazon Simple Workflow Service (Amazon SWF) e può essere recuperato utilizzando il client esterno generato. Questo ti permette di verificare l'ultimo stato di esecuzione del flusso di lavoro. I metodi annotati con `@GetState` non devono acquisire argomenti e non devono avere un tipo restituito `void`. Da questo metodo puoi restituire qualunque tipo che si adatti alle tue esigenze. Nell'esempio citato prima, un oggetto di `MyWorkflowState` (vedi definizione riportata sotto) viene restituito dal metodo utilizzato per archiviare uno stato della stringa e una percentuale numerica completati. Il metodo dovrebbe eseguire l'accesso di sola lettura dell'oggetto dell'implementazione del flusso di lavoro e viene richiamato in modo sincronico, il che non permette l'utilizzo di operazioni asincrone come i metodi di chiamata con `@Asynchronous`. Può essere annotato al massimo un metodo in un'interfaccia di flusso di lavoro con l'annotazione `@GetState`. 

```
public class MyWorkflowState {
   public String status;
   public int percentComplete;
}
```

Analogamente, un set di iniziative viene definito usando un'interfaccia che è annotata con l'annotazione `@Activities`. Ogni metodo nell'interfaccia corrisponde a un'attività, ad esempio: 

```
@Activities(version = "1.0")
@ActivityRegistrationOptions(
     defaultTaskScheduleToStartTimeoutSeconds = 300,
     defaultTaskStartToCloseTimeoutSeconds = 3600)
public interface MyActivities {
    // Overrides values from annotation found on the interface
    @ActivityRegistrationOptions(description = "This is a sample activity",
         defaultTaskScheduleToStartTimeoutSeconds = 100,
         defaultTaskStartToCloseTimeoutSeconds = 60)
    int activity1();

    void activity2(int a);
}
```

L'interfaccia ti permette di raggruppare un set di iniziative relazionate. Puoi definire qualunque numero di attività all'interno dell'interfaccia delle attività e puoi definire il numero di interfacce delle attività che desideri. Analogamente ai metodi `@Execute` e `@Signal`, i metodi di attività possono acquisire qualunque numero di argomenti di qualunque tipo tranne `Promise<T>` o le sue derivate. Il tipo restituito di un'attività non deve essere `Promise<T>` o le sue derivate. 

# Registrazione dei tipi di flusso di lavoro e di attività
<a name="features.registration"></a>

Amazon SWF richiede la registrazione dei tipi di attività e flussi di lavoro prima di poterli utilizzare. Il framework registra automaticamente i flussi di lavoro e le attività nelle implementazioni che aggiungi al lavoratore. Il framework cerca i tipi che implementano flussi di lavoro e attività e li registra con Amazon SWF. Per impostazione predefinita, il framework utilizza le definizioni di interfaccia per dedurre le opzioni di registrazione per i tipi di flusso di lavoro e attività. Tutte le interfacce di flusso di lavoro devono avere l'annotazione `@WorkflowRegistrationOptions` o `@SkipRegistration`. Il lavoratore di flusso di lavoro registra tutti i tipi di flusso di lavoro con cui è configurato che hanno l'annotazione `@WorkflowRegistrationOptions`. Inoltre, ogni metodo di attività deve avere l'annotazione `@ActivityRegistrationOptions` o `@SkipRegistration` oppure una di queste annotazioni deve essere presente nell'interfaccia `@Activities`. Il lavoratore di attività registra tutti i tipi di attività con cui è configurato e a cui si applica un'annotazione `@ActivityRegistrationOptions`. La registrazione è eseguita automaticamente all'avvio di uno dei lavoratori. I tipi di flusso di lavoro e attività che hanno l'annotazione `@SkipRegistration` non sono registrati. Le annotazioni `@ActivityRegistrationOptions` e `@SkipRegistration` hanno la semantica di override e la più specifica viene applicata a un tipo di attività. 

Tieni presente che Amazon SWF non consente di registrare nuovamente o modificare il tipo una volta registrato. Il framework tenterà di registrare tutti i tipi, ma se il tipo è già registrato, la registrazione non verrà ripetuta e non verrà segnalato alcun errore.

Se hai la necessità di modificare le impostazioni registrate, devi registrate una nuova versione del tipo. Puoi anche eseguire l'override delle impostazioni registrate all'avvio di una nuova esecuzione o quando chiami un'attività che utilizza i client generati.

La registrazione richiede un nome di tipo e altre opzioni di registrazione. L'implementazione di default le determina come descritto di seguito.

## Nome e versione del tipo di flusso di lavoro
<a name="features.registration.workflow"></a>

Il framework determina il nome del tipo di flusso di lavoro a partire dall'interfaccia di flusso di lavoro. La forma del nome del tipo di flusso di lavoro predefinito è \$1*prefix*\$1 \$1*name*\$1. Il \$1*prefix*\$1 è impostato sul nome dell'`@Workflow`interfaccia seguito da un '.' e il \$1*name*\$1 è impostato sul nome del `@Execute` metodo. Il nome di default del tipo di flusso di lavoro nell'esempio precedente è `MyWorkflow.startMyWF`. Puoi eseguire l'override del nome di default utilizzando il parametro name del metodo `@Execute`. Il nome di default del tipo di flusso di lavoro nell'esempio è `startMyWF`. Il nome non deve essere una stringa vuota. Nota che quando esegui l'override del nome utilizzando `@Execute`, il framework non aggiunge automaticamente un prefisso davanti al nome. Sei libero di usare il tuo schema di denominazione. 

La versione del flusso di lavoro viene specificata utilizzando il parametro `version` dell'annotazione `@Execute`. Non esiste un valore di default per `version` e quindi deve essere specificato in modo esplicito; `version` è una stringa in formato libero e sei libero di utilizzare uno schema di controllo delle versioni personalizzato. 

## Nome del segnale
<a name="features.registration.signal"></a>

Il nome del segnale può essere specificato utilizzando il parametro name dell'annotazione `@Signal`. Se non è specificato, per impostazione predefinita viene utilizzato il nome del metodo del segnale.

## Nome e versione del tipo di attività
<a name="features.registration.activity"></a>

Il framework determina il nome del tipo di attività a partire dall'interfaccia di attività. La forma del nome del tipo di attività predefinito è \$1*prefix*\$1 \$1*name*\$1. Il \$1*prefix*\$1 è impostato sul nome dell'`@Activities`interfaccia seguito da un '.' e il \$1*name*\$1 è impostato sul nome del metodo. Il valore predefinito \$1*prefix*\$1 può essere sovrascritto nell'`@Activities`annotazione sull'interfaccia delle attività. Puoi anche specificare il nome del tipo di attività utilizzando l'annotazione `@Activity` nel metodo di attività. Nota che quando esegui l'ovveride del nome utilizzando `@Activity`, il framework non aggiungerà automaticamente un prefisso davanti al nome. Sei libero di utilizzare il tuo schema di denominazione.

 La versione dell'attività viene specificata utilizzando il parametro version dell'annotazione `@Activities`. Questa versione è utilizzata come valore di default per tutte le attività definite nell'interfaccia ed è possibile eseguire l'override per una singola attività utilizzando l'annotazione `@Activity`. 

## Elenco di task predefinito
<a name="features.registration.defaulttasklist"></a>

L'elenco di task di default può essere configurato utilizzando le annotazioni `@WorkflowRegistrationOptions` e `@ActivityRegistrationOptions` e impostando il parametro `defaultTaskList`. Per impostazione predefinita, è impostato su `USE_WORKER_TASK_LIST`. Questo è un valore speciale che indica al framework di utilizzare l'elenco di task configurato sull'oggetto lavoratore utilizzato per registrare il tipo di attività o di flusso di lavoro. Puoi anche scegliere di non registrare un elenco di task di default impostando `NO_DEFAULT_TASK_LIST`, nel caso tu voglia che l'elenco di task sia specificato al runtime. Se non è stato registrato alcun elenco di task di default, devi specificarlo all'avvio del flusso di lavoro o quando chiami il metodo di attività utilizzando i parametri `StartWorkflowOptions` e `ActivitySchedulingOptions` sull'overload del client generato per i rispettivi metodi. 

## Altre opzioni di registrazione
<a name="features.registration.other"></a>

Tutte le opzioni di registrazione del flusso di lavoro e del tipo di attività consentite dall'API Amazon SWF possono essere specificate tramite il framework.

Per un elenco completo delle opzioni di registrazione di *flusso di lavoro*, consulta quanto segue:
+ [@Flusso di lavoro](annotations.md#annotations-workflow)
+ [@Execute](annotations.md#annotations-execute)
+ [@WorkflowRegistrationOptions](annotations.md#annotations-workflowregistrationoptions)
+ [@Signal](annotations.md#annotations-signal)

Per un elenco completo delle opzioni di registrazione di *attività*, consulta quanto segue:
+ [@Activity](annotations.md#annotations-activity)
+ [@Activities](annotations.md#annotations-activities)
+ [@ActivityRegistrationOptions](annotations.md#annotations-activityregistration)

Se desideri avere un controllo completo sulla registrazione dei tipi, consulta [Estensibilità dei lavoratori](running.md#running.workerextend).

# Client di attività e flusso di lavoro
<a name="clients"></a>

Client di flusso di lavoro e attività generati dal framework in base alle interfacce `@Workflow` e `@Activities`. Vengono generate interfacce del client separate che contengono metodi e impostazioni che si riferiscono solo al client. Se stai sviluppando utilizzando Eclipse, questa operazione viene eseguita dal plug-in Amazon SWF Eclipse ogni volta che salvi il file contenente l'interfaccia appropriata. Il codice generato viene posizionato nella directory di origine generata nel progetto all'interno dello stesso pacchetto dell'interfaccia. 

**Nota**  
Il nome predefinito della directory utilizzato da Eclipse è .apt\$1generated. Eclipse non mostra le directory nome che inizia con un '.' in Package Explorer. Utilizza un nome diverso della directory se desideri visualizzare i file generati all'interno di Project Explorer. In Eclipse, fai clic sul tasto destro su Package Explorer e poi scegli **Properties** (Proprietà), **Java Compiler** (Compilatore Java), **Annotation processing** (Elaborazione delle annotazioni) e modifica le impostazioni **Generate source directory** (Genera directory di origine).

## Client di flusso di lavoro
<a name="clients.workflow"></a>

Gli artefatti generati per il flusso di lavoro contengono tre interfacce lato client e le classi che le implementano. I client generati includono:
+ Un *client asincrono* che deve essere utilizzato dall'interno dell'implementazione del flusso di lavoro che offre metodi asincroni per avviare le esecuzioni del flusso di lavoro e inviare segnali
+ Un *client esterno* che può essere utilizzato per avviare le esecuzioni, inviare segnali e recuperare lo stato del flusso di lavoro dall'esterno dell'ambito dell'implementazione del flusso di lavoro
+ Un *client autogenerato* che può essere utilizzato per creare flussi di lavoro continui

Ad esempio, le interfacce del client generato per l'interfaccia di esempio `MyWorkflow` sono:

```
//Client for use from within a workflow
public interface MyWorkflowClient extends WorkflowClient
{
    Promise<Void> startMyWF(
       int a, String b);

    Promise<Void> startMyWF(
       int a, String b,
       Promise<?>... waitFor);

    Promise<Void> startMyWF(
       int a, String b,
       StartWorkflowOptions optionsOverride,
       Promise<?>... waitFor);

    Promise<Void> startMyWF(
       Promise<Integer> a,
       Promise<String> b);

    Promise<Void> startMyWF(
       Promise<Integer> a,
       Promise<String> b,
       Promise<?>... waitFor);

    Promise<Void> startMyWF(
       Promise<Integer> a,
       Promise<String> b,
       StartWorkflowOptions optionsOverride,
       Promise<?>... waitFor);

    void signal1(
      int a, int b, String c);
}

//External client for use outside workflows
public interface MyWorkflowClientExternal extends WorkflowClientExternal
{
    void startMyWF(
       int a, String b);

    void startMyWF(
       int a, String b,
       StartWorkflowOptions optionsOverride);

    void signal1(
       int a, int b, String c);

    MyWorkflowState getState();
}

//self client for creating continuous workflows
public interface MyWorkflowSelfClient extends WorkflowSelfClient
{
    void startMyWF(
       int a, String b);

    void startMyWF(
       int a, String b,
       Promise<?>... waitFor);

    void startMyWF(
       int a, String b,
       StartWorkflowOptions optionsOverride,
       Promise<?>... waitFor);

    void startMyWF(
       Promise<Integer> a,
       Promise<String> b);

    void startMyWF(
       Promise<Integer> a,
       Promise<String> b,
       Promise<?>... waitFor);

    void startMyWF(
       Promise<Integer> a,
       Promise<String> b,
       StartWorkflowOptions optionsOverride,
       Promise<?>... waitFor);
```

Le interfacce hanno effettuato l'overloading dei metodi che corrispondono a ciascun metodo nell'interfaccia `@Workflow` che hai dichiarato.

Il client esterno riflette i metodi sull'interfaccia `@Workflow` con un overload aggiuntivo del metodo `@Execute` che accetta `StartWorkflowOptions`. Puoi usare l'overload per passare opzioni aggiuntive quando avvii una nuova esecuzione del flusso di lavoro. Queste opzioni ti permettono di sovrascrivere l'elenco di task predefinito, le impostazioni di timeout e i tag associati all'esecuzione del flusso di lavoro.

Invece, il client asincrono dispone di metodi che ti consentono l'invocazione asincrona del metodo `@Execute`. I seguenti overload del metodo vengono generati nell'interfaccia del client per il metodo `@Execute` nell'interfaccia del flusso di lavoro:

1. Un overload che accetta gli argomenti originali "così come sono". Il tipo restituito dell'overload sarà `Promise<Void>` se il metodo originale ha restituito `void`; altrimenti sarà `Promise<>` come dichiarato nel metodo originale. Per esempio:

   Metodo originale:

   ```
   void startMyWF(int a, String b);
   ```

   Metodo generato:

   ```
   Promise<Void> startMyWF(int a, String b);
   ```

   Questo overload deve essere usato quando tutti gli argomenti del flusso di lavoro sono disponibili e non devono essere attesi.

1. Un overload che accetta gli argomenti originali "così come sono" e argomenti variabili aggiuntivi del tipo `Promise<?>`. Il tipo restituito dell'overload sarà `Promise<Void>` se il metodo originale ha restituito `void`; altrimenti sarà `Promise<>` come dichiarato nel metodo originale. Per esempio: 

   Metodo originale:

   ```
   void startMyWF(int a, String b);
   ```

   Metodo generato:

   ```
   Promise<void> startMyWF(int a, String b, Promise<?>...waitFor);
   ```

   Questo overload deve essere usato quando tutti gli argomenti del flusso di lavoro sono disponibili e non devono essere attesi, ma desideri attendere che altre promesse siano pronte. L'argomento variabile può essere usato per passare gli oggetti `Promise<?>` che non sono stati dichiarati come argomenti, ma desideri attendere prima di eseguire la chiamata. 

1. Un overload che accetta gli argomenti originali "così come sono", un argomento aggiuntivo del tipo `StartWorkflowOptions` e argomenti variabili aggiuntivi del tipo `Promise<?>`. Il tipo restituito dell'overload sarà `Promise<Void>` se il metodo originale ha restituito `void`; altrimenti sarà `Promise<>` come dichiarato nel metodo originale. Per esempio:

   Metodo originale:

   ```
   void startMyWF(int a, String b);
   ```

   Metodo generato:

   ```
   Promise<void> startMyWF(
      int a,
      String b,
      StartWorkflowOptions optionOverrides,
      Promise<?>...waitFor);
   ```

   Questo overload deve essere usato quando tutti gli argomenti del flusso di lavoro sono disponibili e non devono essere attesi, quando desideri sovrascrivere le impostazioni predefinite usate per avviare l'esecuzione del flusso di lavoro o quando desideri attendere che altre promesse siano pronte. L'argomento variabile può essere usato per passare gli oggetti `Promise<?>` che non sono stati dichiarati come argomenti, ma desideri attendere prima di eseguire la chiamata. 

1. Un overload in cui ogni argomento nel metodo originale viene sostituito con un wrapper `Promise<>`. Il tipo restituito dell'overload sarà `Promise<Void>` se il metodo originale ha restituito `void`; altrimenti sarà `Promise<>` come dichiarato nel metodo originale. Per esempio: 

   Metodo originale: 

   ```
   void startMyWF(int a, String b);
   ```

   Metodo generato: 

   ```
   Promise<Void> startMyWF(
      Promise<Integer> a,
      Promise<String> b);
   ```

   Questo overload deve essere usato quando gli argomenti da passare all'esecuzione del flusso di lavoro devono essere valutati in modo asincrono. Non verrà eseguita una chiamata all'overload del metodo fino a quando tutti gli argomenti passati non diventano pronti.

   Se alcuni degli argomenti sono già pronti, allora puoi convertirli in un oggetto `Promise` che è già pronto attraverso il metodo `Promise.asPromise(value)`. Per esempio:

   ```
   Promise<Integer> a = getA();
   String b = getB();
   startMyWF(a, Promise.asPromise(b));
   ```

1. Un overload in cui ogni argomento nel metodo originale viene sostituito con un wrapper `Promise<>`. L'overload dispone anche di argomenti variabili aggiuntivi del tipo `Promise<?>`. Il tipo restituito dell'overload sarà `Promise<Void>` se il metodo originale ha restituito `void`; altrimenti sarà `Promise<>` come dichiarato nel metodo originale. Per esempio:

   Metodo originale: 

   ```
   void startMyWF(int a, String b);
   ```

   Metodo generato: 

   ```
   Promise<Void> startMyWF(
      Promise<Integer> a,
      Promise<String> b,
      Promise<?>...waitFor);
   ```

   Questo overload deve essere usato quando gli argomenti da passare all'esecuzione del flusso di lavoro devono essere valutati in modo asincrono e desideri attendere che altre promesse siano pronte. Non verrà eseguita una chiamata all'overload del metodo fino a quando tutti gli argomenti passati non diventano pronti.

1. Un overload in cui ogni argomento nel metodo originale viene sostituito con un wrapper `Promise<?>`. L'overload dispone anche di un argomento aggiuntivo del tipo `StartWorkflowOptions` e di argomenti variabili del tipo `Promise<?>`. Il tipo restituito dell'overload sarà `Promise<Void>` se il metodo originale ha restituito `void`; altrimenti sarà `Promise<>` come dichiarato nel metodo originale. Per esempio: 

   Metodo originale: 

   ```
   void startMyWF(int a, String b);
   ```

   Metodo generato: 

   ```
   Promise<Void> startMyWF(
      Promise<Integer> a,
      Promise<String> b,
      StartWorkflowOptions optionOverrides,
      Promise<?>...waitFor);
   ```

   Utilizza questo overload quando gli argomenti da passare all'esecuzione del flusso di lavoro verranno valutati in modo asincrono e desideri sovrascrivere le impostazioni predefinite utilizzate per avviare l'esecuzione del flusso di lavoro. Non verrà eseguita una chiamata all'overload del metodo fino a quando tutti gli argomenti passati non diventano pronti.

Viene inoltre generato un metodo corrispondente a ciascun segnale nell'interfaccia del flusso di lavoro, ad esempio:

Metodo originale:

```
void signal1(int a, int b, String c);
```

Metodo generato:

```
void signal1(int a, int b, String c);
```

Il client asincrono non contiene un metodo che corrisponde al metodo annotato con `@GetState` nell'interfaccia originale. Poiché il recupero dello stato richiede una chiamata al servizio Web, non è adatto all'uso all'interno di un flusso di lavoro. Quindi, viene fornito soltanto attraverso il client esterno. 

Il client autogenerato deve essere utilizzato dall'interno di un flusso di lavoro per avviare una nuova esecuzione dopo il completamento di quella attuale. I metodi su questo client sono simili a quelli sul client asincrono, ma restituiscono `void`. Questo client non dispone di metodi che corrispondono ai metodi annotati con `@Signal` e `@GetState`. Per ulteriori dettagli, consulta [Flussi di lavoro continui](continuous.md). 

I client generati derivano da interfacce di base: `WorkflowClient` e `WorkflowClientExternal`, rispettivamente, che forniscono metodi che puoi utilizzare per annullare o terminare l'esecuzione del flusso di lavoro. Per ulteriori dettagli su queste interfacce, consulta la documentazione AWS SDK per Java .

I client generati ti permettono di interagire con le esecuzioni del flusso di lavoro in modo fortemente tipizzato. Una volta creata, un'istanza di un client generato è legata a un'esecuzione del flusso di lavoro specifica e può essere utilizzata soltanto per quell'esecuzione. Inoltre, il framework fornisce client dinamici che non sono specifici per un tipo o un'esecuzione del flusso di lavoro. I client generati si basano su questo client. Puoi anche usare direttamente questi client. Consulta la sezione su [Client dinamici](#dynamicclients).

Il framework genera inoltre factory per creare client fortemente tipizzati. Le factoy del client generato per l'interfaccia di esempio `MyWorkflow` sono: 

```
//Factory for clients to be used from within a workflow
public interface MyWorkflowClientFactory
   extends WorkflowClientFactory<MyWorkflowClient>
{
}

//Factory for clients to be used outside the scope of a workflow
public interface MyWorkflowClientExternalFactory
{
   GenericWorkflowClientExternal getGenericClient();
   void setGenericClient(GenericWorkflowClientExternal genericClient);
   DataConverter getDataConverter();
   void setDataConverter(DataConverter dataConverter);
   StartWorkflowOptions getStartWorkflowOptions();
   void setStartWorkflowOptions(StartWorkflowOptions startWorkflowOptions);
   MyWorkflowClientExternal getClient();
   MyWorkflowClientExternal getClient(String workflowId);
   MyWorkflowClientExternal getClient(WorkflowExecution workflowExecution);
   MyWorkflowClientExternal getClient(
      WorkflowExecution workflowExecution,
      GenericWorkflowClientExternal genericClient,
      DataConverter dataConverter,
      StartWorkflowOptions options);
}
```

L'interfaccia di base `WorkflowClientFactory` è: 

```
public interface WorkflowClientFactory<T> {
    GenericWorkflowClient getGenericClient();
    void setGenericClient(GenericWorkflowClient genericClient);
    DataConverter getDataConverter();
    void setDataConverter(DataConverter dataConverter);
    StartWorkflowOptions getStartWorkflowOptions();
    void setStartWorkflowOptions(StartWorkflowOptions startWorkflowOptions);
    T getClient();
    T getClient(String workflowId);
    T getClient(WorkflowExecution execution);
    T getClient(WorkflowExecution execution,
                StartWorkflowOptions options);
    T getClient(WorkflowExecution execution,
                StartWorkflowOptions options,
                DataConverter dataConverter);
}
```

Devi utilizzare queste factory per creare istanze del client. La factory ti permette di configurare il client generico (il client generico deve essere utilizzato per eseguire l'implementazione personalizzata del client) e il `DataConverter` utilizzato dal client per effettuare il marshalling dei dati, oltre alle opzioni utilizzate per avviare l'*esecuzione del flusso di lavoro*. Per ulteriori dettagli, consulta le sezioni [DataConverters](dataconverters.md) e [Esecuzioni del flusso di lavoro figlio](childworkflow.md). `StartWorkflowOptions`Contiene impostazioni che è possibile utilizzare per ignorare le impostazioni predefinite, ad esempio i timeout, specificate al momento della registrazione. Per maggiori dettagli sulla classe, consultate la documentazione. `StartWorkflowOptions` AWS SDK per Java 

Il client esterno può essere utilizzato per avviare le esecuzioni del flusso di lavoro dall'esterno dell'ambito di un flusso di lavoro mentre il client asincrono può essere utilizzato per avviare un'esecuzione del flusso di lavoro dal codice all'interno di un flusso di lavoro. Per avviare un'esecuzione, devi semplicemente usare il client generato per chiamare il metodo che corrisponde al metodo annotato con `@Execute` nell'interfaccia del flusso di lavoro.

Il framework genera inoltre classi di implementazioni per le interfacce del client. Questi client creano e inviano richieste ad Amazon SWF per eseguire l'azione appropriata. La versione client del `@Execute` metodo avvia un'esecuzione di un nuovo flusso di lavoro o crea un'esecuzione del flusso di lavoro secondario utilizzando Amazon SWF APIs. Analogamente, la versione client del `@Signal` metodo utilizza Amazon SWF APIs per inviare un segnale.

**Nota**  
Il client di workflow esterno deve essere configurato con il client e il dominio Amazon SWF. Puoi utilizzare il costruttore client factory che li accetta come parametri o passare un'implementazione client generica già configurata con il client e il dominio Amazon SWF.  
Il framework percorre la gerarchia del tipo dell'interfaccia del flusso di lavoro e inoltre genera interfacce del client per le interfacce del flusso di lavoro padre e deriva da esse.

## Client di attività
<a name="clients.activity"></a>

Analogamente al client del flusso di lavoro, viene generato un client per ogni interfaccia annotata con `@Activities`. Gli artefatti generati includono un'interfaccia lato client e una classe client. L'interfaccia generata per l'interfaccia di esempio `@Activities` sopra indicata (`MyActivities`) è la seguente:

```
public interface MyActivitiesClient extends ActivitiesClient
{
  Promise<Integer> activity1();
  Promise<Integer> activity1(Promise<?>... waitFor);
  Promise<Integer> activity1(ActivitySchedulingOptions optionsOverride,
                             Promise<?>... waitFor);
  Promise<Void> activity2(int a);
  Promise<Void> activity2(int a,
                          Promise<?>... waitFor);
  Promise<Void> activity2(int a,
                          ActivitySchedulingOptions optionsOverride,
                          Promise<?>... waitFor);
  Promise<Void> activity2(Promise<Integer> a);
  Promise<Void> activity2(Promise<Integer> a,
                          Promise<?>... waitFor);
  Promise<Void> activity2(Promise<Integer> a,
                          ActivitySchedulingOptions optionsOverride,
                          Promise<?>... waitFor);
}
```

L'interfaccia contiene un set di metodi su cui è stato effettuato l'overloading che corrispondono a ciascun metodo di attività nell'interfaccia `@Activities`. Tali overload sono forniti per comodità e permettono di chiamare le attività in modo asincrono. I seguenti overload del metodo vengono generati nell'interfaccia del client per ogni metodo di attività nell'interfaccia `@Activities`: 

1. Un overload che accetta gli argomenti originali "così come sono". Il tipo restituito per questo overload è `Promise<T>`, dove `T` è il tipo restituito del metodo originale. Per esempio: 

   Metodo originale: 

   ```
   void activity2(int foo);
   ```

   Metodo generato: 

   ```
   Promise<Void> activity2(int foo);
   ```

   Questo overload deve essere usato quando tutti gli argomenti del flusso di lavoro sono disponibili e non devono essere attesi. 

1. Un overload che accetta gli argomenti originali "così come sono", un argomento del tipo `ActivitySchedulingOptions` e argomenti variabili aggiuntivi del tipo `Promise<?>`. Il tipo restituito per questo overload è `Promise<T>`, dove `T` è il tipo restituito del metodo originale. Per esempio:

   Metodo originale: 

   ```
   void activity2(int foo);
   ```

   Metodo generato: 

   ```
   Promise<Void> activity2(
     int foo,
     ActivitySchedulingOptions optionsOverride,
     Promise<?>... waitFor);
   ```

   Questo overload deve essere usato quando tutti gli argomenti del flusso di lavoro sono disponibili e non devono essere attesi, quando desideri sovrascrivere le impostazioni predefinite o quando desideri attendere che un'altra `Promise` sia pronta. Gli argomenti variabili possono essere usati per passare gli oggetti `Promise<?>` aggiuntivi che non sono stati dichiarati come argomenti, ma desideri attendere prima di eseguire la chiamata. 

1. Un overload in cui ogni argomento nel metodo originale viene sostituito con un wrapper `Promise<>`. Il tipo restituito per questo overload è `Promise<T>`, dove `T` è il tipo restituito del metodo originale. Per esempio:

   Metodo originale: 

   ```
   void activity2(int foo);
   ```

   Metodo generato: 

   ```
   Promise<Void> activity2(Promise<Integer> foo);
   ```

   Questo overload deve essere usato quando gli argomenti da passare all'attività verranno valutati in modo asincrono. Non verrà eseguita una chiamata all'overload del metodo fino a quando tutti gli argomenti passati non diventano pronti.

1. Un overload in cui ogni argomento nel metodo originale viene sostituito con un wrapper `Promise<>`. L'overload dispone anche di un argomento aggiuntivo del tipo `ActivitySchedulingOptions` e di argomenti variabili del tipo `Promise<?>`. Il tipo restituito per questo overload è `Promise<T>`, dove `T` è il tipo restituito del metodo originale. Per esempio: 

   Metodo originale: 

   ```
   void activity2(int foo);
   ```

   Metodo generato: 

   ```
   Promise<Void> activity2(
      Promise<Integer> foo,
      ActivitySchedulingOptions optionsOverride,
      Promise<?>...waitFor);
   ```

   Questo overload deve essere usato quando tutti gli argomenti da passare all'attività verranno valutati in modo asincrono, quando desideri sovrascrivere le impostazioni predefinite registrate con il tipo o quando desideri attendere che un altro oggetto `Promise` sia pronto. Non verrà eseguita una chiamata all'overload del metodo fino a quando tutti gli argomenti passati non diventano pronti. La classe del client generata implementa questa interfaccia. L'implementazione di ogni metodo di interfaccia crea e invia una richiesta ad Amazon SWF per pianificare un'attività del tipo appropriato utilizzando Amazon SWF. APIs 

1. Un overload che accetta gli argomenti originali "così come sono" e argomenti variabili aggiuntivi del tipo `Promise<?>`. Il tipo restituito per questo overload è `Promise<T>`, dove `T` è il tipo restituito del metodo originale. Per esempio: 

   Metodo originale: 

   ```
   void activity2(int foo);
   ```

   Metodo generato: 

   ```
   Promise< Void > activity2(int foo,
                                Promise<?>...waitFor);
   ```

   Questo overload deve essere usato quando tutti gli argomenti dell'attività sono disponibili e non devono essere attesi, ma desideri attendere che altri oggetti `Promise` siano pronti. 

1. Un overload in cui ogni argomento del metodo originale viene sostituito con un wrapper `Promise` e argomenti variabili aggiuntivi del tipo `Promise<?>`. Il tipo restituito per questo overload è `Promise<T>`, dove `T` è il tipo restituito del metodo originale. Per esempio: 

   Metodo originale: 

   ```
   void activity2(int foo);
   ```

   Metodo generato: 

   ```
   Promise<Void> activity2(
     Promise<Integer> foo,
     Promise<?>... waitFor);
   ```

   Questo overload deve essere usato quando tutti gli argomenti dell'attività verranno attesi in modo asincrono e desideri attendere che altre `Promise` siano pronte. Verrà eseguita una chiamata asincrona all'overload del metodo fino a quando tutti gli oggetti `Promise` passati non diventano pronti. 

Il client di attività generato dispone inoltre di un metodo protetto che corrisponde a ogni metodo di attività, nominato `{activity method name}Impl()`, a cui tutti gli overload dell'attività eseguono una chiamata. Puoi sovrascrivere questo metodo per creare implementazioni del client fittizie. Questo metodo accetta come argomenti tutti gli argomenti per il metodo originale nei wrapper `Promise<>`, `ActivitySchedulingOptions` e argomenti variabili del tipo `Promise<?>`. Per esempio:

Metodo originale: 

```
void activity2(int foo);
```

Metodo generato: 

```
Promise<Void> activity2Impl(
   Promise<Integer> foo,
   ActivitySchedulingOptions optionsOverride,
   Promise<?>...waitFor);
```

## Opzioni di programmazione
<a name="schedulingoptions"></a>

Il client di attività generato ti permette di passare in `ActivitySchedulingOptions` come argomento. La `ActivitySchedulingOptions` struttura contiene impostazioni che determinano la configurazione dell'attività che il framework pianifica in Amazon SWF. Queste impostazioni sovrascrivono quelle predefinite specificate come opzioni di registrazione. Per specificare le opzioni di pianificazione in modo dinamico, crea un oggetto `ActivitySchedulingOptions`, configuralo come preferisci e passalo al metodo di attività. Nell'esempio seguente abbiamo specificato l'elenco di task che deve essere utilizzato per il task di attività. Questa operazione sovrascrive l'elenco di task registrato predefinito per l'invocazione dell'attività.

```
public class OrderProcessingWorkflowImpl implements OrderProcessingWorkflow {

    OrderProcessingActivitiesClient activitiesClient
            = new OrderProcessingActivitiesClientImpl();

    // Workflow entry point
    @Override
    public void processOrder(Order order) {
        Promise<Void> paymentProcessed = activitiesClient.processPayment(order);
        ActivitySchedulingOptions schedulingOptions
             = new ActivitySchedulingOptions();
        if (order.getLocation() == "Japan") {
            schedulingOptions.setTaskList("TasklistAsia");
        } else {
            schedulingOptions.setTaskList("TasklistNorthAmerica");
        }

        activitiesClient.shipOrder(order,
                                   schedulingOptions,
                                   paymentProcessed);
    }
}
```

## Client dinamici
<a name="dynamicclients"></a>

Oltre ai client generati, il framework fornisce anche client generici `DynamicActivityClient` che puoi utilizzare per avviare dinamicamente esecuzioni di flussi di lavoro, inviare segnali, pianificare attività, ecc. `DynamicWorkflowClient` Ad esempio, potresti voler pianificare un'attività il cui tipo non è noto in fase di progettazione. Puoi utilizzare `DynamicActivityClient` per pianificare questo tipo di task di attività. Analogamente, puoi pianificare in modo dinamico un'esecuzione del flusso di lavoro figlio utilizzando `DynamicWorkflowClient`. Nel seguente esempio, il flusso di lavoro cerca l'attività da un database e utilizza il client dell'attività dinamico per pianificarla:

```
//Workflow entrypoint
@Override
public void start() {
   MyActivitiesClient client = new MyActivitiesClientImpl();
  Promise<ActivityType> activityType
      = client.lookUpActivityFromDB();
  Promise<String> input = client.getInput(activityType);
  scheduleDynamicActivity(activityType,
                          input);
}
@Asynchronous
void scheduleDynamicActivity(Promise<ActivityType> type,
                             Promise<String> input){
  Promise<?>[] args = new Promise<?>[1];
   args[0] = input;
   DynamicActivitiesClient activityClient
       = new DynamicActivitiesClientImpl();
   activityClient.scheduleActivity(type.get(),
                                   args,
                                   null,
                                   Void.class);
}
```

Per ulteriori dettagli, consulta la documentazione. AWS SDK per Java 

### Segnalare e annullare le esecuzioni del flusso di lavoro
<a name="executioncontext.signal"></a>

Il client del flusso di lavoro generato dispone di metodi corrispondenti a ogni segnale che possono essere inviati al flusso di lavoro. Puoi usarli dall'interno di un flusso di lavoro per inviare segnali ad altre esecuzioni del flusso di lavoro. Questa operazione fornisce un meccanismo tipizzato per l'invio dei segnali. Tuttavia, a volte può essere necessario determinare dinamicamente il nome del segnale, ad esempio quando il nome del segnale viene ricevuto in un messaggio. Puoi usare il client del flusso di lavoro dinamico per inviare segnali in modo dinamico a qualunque esecuzione del flusso di lavoro. Analogamente, puoi usare il client per richiedere l'annullamento di un'altra esecuzione del flusso di lavoro.

Nel seguente esempio, il flusso di lavoro cerca l'esecuzione per inviare un segnale da un database e invia il segnale in modo dinamico tramite il client del flusso di lavoro dinamico.

```
//Workflow entrypoint
public void start()
{
  MyActivitiesClient client = new MyActivitiesClientImpl();
  Promise<WorkflowExecution> execution = client.lookUpExecutionInDB();
  Promise<String> signalName = client.getSignalToSend();
  Promise<String> input = client.getInput(signalName);
  sendDynamicSignal(execution, signalName, input);
}

@Asynchronous
void sendDynamicSignal(
   Promise<WorkflowExecution> execution,
   Promise<String> signalName,
   Promise<String> input)
{
   DynamicWorkflowClient workflowClient
      = new DynamicWorkflowClientImpl(execution.get());
   Object[] args = new Promise<?>[1];
   args[0] = input.get();
   workflowClient.signalWorkflowExecution(signalName.get(), args);
}
```

# Implementazione del flusso di lavoro
<a name="workflowimpl"></a>

Per implementare un flusso di lavoro, scrivi una classe che implementa l'interfaccia `@Workflow` desiderata. Ad esempio, l'interfaccia del flusso di lavoro di esempio (`MyWorkflow`) può essere implementata come segue: 

```
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);
  }
}
```

Il metodo `@Execute` in questa classe è il punto di ingresso della logica del flusso di lavoro. Poiché il framework utilizza il replay per ricostruire lo stato dell'oggetto quando deve essere elaborata un'attività decisionale, viene creato un nuovo oggetto per ogni attività decisionale.

L'utilizzo di `Promise<T>` come parametro non è consentito nel metodo `@Execute` in un'interfaccia `@Workflow`. Questo perché una chiamata asincrona è una decisione esclusiva dell'intermediario. L'implementazione del flusso di lavoro in sé non dipende dalla modalità di invocazione (sincrona o asincrona). Di conseguenza, l'interfaccia client generata ha overload che accettano i parametri `Promise<T>` in modo che questi metodi possano essere chiamati in modo asincrono. 

Il tipo di restituzione di un metodo `@Execute` può essere solo `void` o `Promise<T>`. Ricorda che un tipo di restituzione del client esterno corrispondente è `void` e non `Promise<>`. Poiché il client esterno non è progettato per essere utilizzato dal codice asincrono, il client esterno non restituisce oggetti. `Promise` Per ottenere i risultati delle esecuzioni dei flussi di lavoro dichiarati esternamente, è possibile progettare il flusso di lavoro in modo che aggiorni lo stato in un archivio dati esterno tramite un'attività. La visibilità di Amazon SWF APIs può essere utilizzata anche per recuperare il risultato di un flusso di lavoro a fini diagnostici. Non è consigliabile utilizzare la visibilità APIs per recuperare i risultati delle esecuzioni dei flussi di lavoro come pratica generale, poiché queste chiamate API potrebbero essere limitate da Amazon SWF. La visibilità APIs richiede l'identificazione dell'esecuzione del flusso di lavoro utilizzando una struttura. `WorkflowExecution` Puoi ottenere questa struttura dal client di flusso di lavoro generato chiamando il metodo `getWorkflowExecution`. Questo metodo restituisce la struttura `WorkflowExecution` corrispondente all'esecuzione del flusso di lavoro a cui il client è legato. Consulta il [riferimento all'API di Amazon Simple Workflow Service](https://docs.aws.amazon.com/amazonswf/latest/apireference/) per maggiori dettagli sulla visibilità APIs. 

Quando chiami le attività dall'implementazione del flusso di lavoro, devi utilizzare il client di attività generato. Analogamente, per inviare segnali, devi utilizzare i client di flusso di lavoro generati. 

## Contesto di decisione
<a name="workflowimpl.decisioncontext"></a>

Il framework fornisce un contesto di ambiente ogni volta che il codice del flusso di lavoro viene eseguito dal framework. Questo contesto offre funzionalità specifiche a cui puoi accedere nell'implementazione del flusso di lavoro, ad esempio la creazione di un timer. Consulta la sezione relativa a [Contesto di esecuzione](executioncontext.md) per ulteriori informazioni.

## Esposizione dello stato dell'esecuzione
<a name="workflowimpl.executionstate"></a>

Amazon SWF ti consente di aggiungere uno stato personalizzato nella cronologia del flusso di lavoro. L'ultimo stato riportato dall'esecuzione del flusso di lavoro ti viene restituito tramite chiamate di visibilità al servizio Amazon SWF e nella console Amazon SWF. Ad esempio, in un flusso di lavoro di elaborazione dell'ordine, puoi segnalare lo stato dell'ordine in fasi diverse come "ordine ricevuto", ordine spedito" e così via. In Java, ciò avviene tramite un metodo sull'interfaccia del flusso di lavoro che viene annotato con l'annotazione. AWS Flow Framework `@GetState` Quando il decisore ha terminato l'elaborazione di un task di decisione, chiama il metodo per ricevere l'ultimo stato dall'implementazione del flusso di lavoro. A parte le chiamate di visibilità, lo stato può essere recuperato anche utilizzando il client esterno generato (che utilizza internamente le chiamate API di visibilità).

L'esempio seguente mostra come configurare il contesto di esecuzione.

```
@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()
   {
      ...
    }
}
```

Si può utilizzare il client esterno generato per recuperare in qualsiasi momento l'ultimo stato dell'esecuzione del flusso di lavoro.

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

Nell'esempio precedente, lo stato di esecuzione è segnalato in varie fasi. Quando inizia l'istanza del flusso di lavoro, `periodicWorkflow` segnala lo stato iniziale come "Appena iniziata". Ogni chiamata a `callPeriodicActivity` aggiorna lo stato del flusso di lavoro. Una volta che `activity1` è stata chiamata 100 volte, il metodo esegue la restituzione e l'istanza del flusso di lavoro è completata.

## Locali del flusso di lavoro
<a name="workflowimpl.workflowlocals"></a>

A volte, puoi avere la necessità di utilizzare le variabili statiche nell'implementazione del flusso di lavoro. Ad esempio, puoi voler archiviare un contatore a cui è stato effettuato l'accesso da vari posti (forse classi diverse) nell'implementazione del flusso di lavoro. Tuttavia, non puoi affidarti a variabili statiche nei flussi di lavoro, perché le variabili statiche sono condivise tra i thread, il che rappresenta un problema, perché un lavoratore elabora task di decisione diversi su thread diversi nello stesso momento. In alternativa, puoi archiviare questo stato in un campo dell'implementazione del flusso di lavoro, ma poi devi trasferire l'oggetto dell'implementazione. A questo scopo, il framework fornisce una classe `WorkflowExecutionLocal<?>`. Ogni stato che deve avere una variabile statica come semantica deve essere mantenuto come istanza locale utilizzando `WorkflowExecutionLocal<?>`. Puoi dichiarare e utilizzare una variabile statica di questo tipo. Ad esempio, nel seguente frammento di codice, un `WorkflowExecutionLocal<String>` viene utilizzato per archiviare un nome utente.

```
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());
  }
}
```

# Implementazione di attività
<a name="activityimpl"></a>

Le attività vengono implementate fornendo un'implementazione dell'interfaccia `@Activities`. The AWS Flow Framework for Java utilizza le istanze di implementazione delle attività configurate sul worker per elaborare le attività in fase di esecuzione. Il lavoratore trova automaticamente l'implementazione di attività del tipo corretto. 

Puoi utilizzare proprietà e campi per trasferire le risorse alle istanze di attività, ad esempio le connessioni del database. Poiché è possibile accedere all'oggetto di implementazione dell'attività da più thread, le risorse condivise devono essere thread-safe. 

Ricorda che l'implementazione di attività non accetta parametri di tipo `Promise<>` e non restituisce oggetti di quel tipo. Questo perché l'implementazione di attività non deve dipendere dal modo in cui è stata invocata (sincrono o asincrono). 

L'interfaccia delle attività mostrata in precedenza può essere implementata in questo modo: 

```
public class MyActivitiesImpl implements MyActivities {

   @Override
   @ManualActivityCompletion
   public int activity1(){
      //implementation
   }

   @Override
   public void activity2(int foo){
     //implementation
   }
}
```

L'attività di implementazione ha a disposizione un contesto locale di thread per recuperare l'oggetto del task, l'oggetto del convertitore di dati in uso ecc. Si può accedere al contesto attuale tramite `ActivityExecutionContextProvider.getActivityExecutionContext()`. Per maggiori dettagli, consulta la AWS SDK per Java documentazione `ActivityExecutionContext` e la sezione dedicata[Contesto di esecuzione](executioncontext.md). 

## Completamento manuale della attività
<a name="activityimpl.complete"></a>

L'annotazione `@ManualActivityCompletion` nell'esempio precedente è opzionale. È consentita solo sui metodi che implementano un'attività e viene utilizzata per configurare l'attività perché non sia completata automaticamente in fase di restituzione del metodo di attività. Ciò può essere utile quando si desidera completare l'attività in modo asincrono, ad esempio manualmente dopo il completamento di un'azione umana.

Per impostazione predefinita, il framework considera l'attività completata alla fase di restituzione del metodo di attività. Ciò significa che l'addetto all'attività segnala il completamento dell'attività ad Amazon SWF e gli fornisce i risultati (se presenti). Tuttavia, ci sono casi d'uso in cui non è consigliabile che il task di attività sia indicato come completato in questa fase. Questo è particolarmente utile quando stai modellando task umani. Ad esempio, il metodo di attività può inviare una e-mail alla persona che deve completare una parte del lavoro prima del completamento del task di attività. In questi casi, puoi annotare il metodo di attività con `@ManualActivityCompletion` per comunicare al lavoratore di attività che non la deve completare automaticamente. Per completare l'attività manualmente, puoi utilizzare il metodo `ManualActivityCompletionClient` fornito nel framework o utilizzare il `RespondActivityTaskCompleted` metodo sul client Java Amazon SWF fornito nell'SDK Amazon SWF. Per ulteriori dettagli, consulta la documentazione. AWS SDK per Java 

Per completare il task di attività, devi fornire un token del task. Il task token viene utilizzato da Amazon SWF per identificare in modo univoco le attività. Puoi accedere al token dal `ActivityExecutionContext` nell'implementazione di attività. Devi trasferire il token alla parte responsabile del completamento del task. Il token può essere recuperato dal `ActivityExecutionContext` chiamando `ActivityExecutionContextProvider.getActivityExecutionContext().getTaskToken()`.

L'attività `getName` dell'esempio di Hello World può essere implementata per inviare un'e-mail in cui si chiede a qualcuno di esprimere un messaggio di saluto:

```
@ManualActivityCompletion
@Override
public String getName() throws InterruptedException {
    ActivityExecutionContext executionContext
         = contextProvider.getActivityExecutionContext();
    String taskToken = executionContext.getTaskToken();
    sendEmail("abc@xyz.com",
         "Please provide a name for the greeting message and close task with token: " + taskToken);
    return "This will not be returned to the caller";
}
```

Si può utilizzare il seguente frammento di codice per il saluto e chiudere il task utilizzando il `ManualActivityCompletionClient`. In alternativa, il task può anche non andare a buon fine:

```
public class CompleteActivityTask {

    public void completeGetNameActivity(String taskToken) {

        AmazonSimpleWorkflow swfClient
           = new AmazonSimpleWorkflowClient(...); // use AWS access keys
        ManualActivityCompletionClientFactory manualCompletionClientFactory
           = new ManualActivityCompletionClientFactoryImpl(swfClient);
        ManualActivityCompletionClient manualCompletionClient
           = manualCompletionClientFactory.getClient(taskToken);
        String result = "Hello World!";
        manualCompletionClient.complete(result);
    }

    public void failGetNameActivity(String taskToken, Throwable failure) {
        AmazonSimpleWorkflow swfClient
           = new AmazonSimpleWorkflowClient(...); // use AWS access keys
        ManualActivityCompletionClientFactory manualCompletionClientFactory
           = new ManualActivityCompletionClientFactoryImpl(swfClient);
        ManualActivityCompletionClient manualCompletionClient
           = manualCompletionClientFactory.getClient(taskToken);
        manualCompletionClient.fail(failure);
    }
}
```

# AWS Lambda Attività di implementazione
<a name="lambda-task"></a>

**Topics**
+ [Informazioni su AWS Lambda](#about-aws-lambda)
+ [Vantaggi e limiti dell'utilizzo delle attività Lambda](#benefits-limitations-lambda-tasks)
+ [Utilizzo delle attività Lambda nei flussi di lavoro AWS Flow Framework per Java](#using-lambda-tasks-in-java-flow-workflows)
+ [Visualizza l'esempio HelloLambda](#see-lambda-sample)

## Informazioni su AWS Lambda
<a name="about-aws-lambda"></a>

AWS Lambda è un servizio di elaborazione completamente gestito che esegue il codice in risposta a eventi generati da codice personalizzato o da vari AWS servizi come Amazon S3, DynamoDB, Amazon Kinesis, Amazon SNS e Amazon Cognito. Per ulteriori informazioni su Lambda, consulta la [Guida per gli sviluppatori di AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/).

Amazon Simple Workflow Service fornisce un task Lambda che consente di eseguire funzioni Lambda al posto o insieme alle attività tradizionali di Amazon SWF.

**Importante**  
Sul tuo AWS account verranno addebitate le esecuzioni (richieste) Lambda eseguite da Amazon SWF per tuo conto. [Per informazioni dettagliate sui prezzi di Lambda, consulta https://aws.amazon.com/lambda/ pricing/.](https://aws.amazon.com/lambda/pricing/)

## Vantaggi e limiti dell'utilizzo delle attività Lambda
<a name="benefits-limitations-lambda-tasks"></a>

L'utilizzo delle attività Lambda al posto di un'attività tradizionale di Amazon SWF offre numerosi vantaggi:
+ Le attività Lambda non devono essere registrate o sottoposte a versioni come i tipi di attività di Amazon SWF.
+ Puoi utilizzare qualsiasi funzione Lambda esistente che hai già definito nei tuoi flussi di lavoro.
+ Le funzioni Lambda vengono richiamate direttamente da Amazon SWF; non è necessario implementare un programma di lavoro per eseguirle come è necessario fare con le attività tradizionali.
+ Lambda fornisce metriche e log per tracciare e analizzare le esecuzioni delle funzioni.

L'utilizzo di task Lambda comporta anche alcuni limiti che è necessario conoscere:
+ Le attività Lambda possono essere eseguite solo nelle AWS regioni che forniscono supporto per Lambda. Consulta [le regioni e gli endpoint Lambda](https://docs.aws.amazon.com/general/latest/gr/rande.html#lambda_region) nel *riferimento generale di Amazon Web Services* per dettagli sulle regioni attualmente supportate per Lambda.
+ Le attività Lambda sono attualmente supportate solo dall'API HTTP SWF di base e in Java. AWS Flow Framework Al momento non è disponibile alcun supporto per le attività Lambda in AWS Flow Framework for Ruby.

## Utilizzo delle attività Lambda nei flussi di lavoro AWS Flow Framework per Java
<a name="using-lambda-tasks-in-java-flow-workflows"></a>

Esistono tre requisiti per utilizzare le attività Lambda nei flussi di lavoro AWS Flow Framework per Java:
+ Una funzione Lambda da eseguire. Puoi usare qualsiasi funzione Lambda che hai definito. Per ulteriori informazioni su come creare funzioni Lambda, consulta la Guida per gli [AWS Lambda sviluppatori](https://docs.aws.amazon.com/lambda/latest/dg/).
+ Un ruolo IAM che fornisce l'accesso per eseguire funzioni Lambda dai flussi di lavoro Amazon SWF.
+ Codice per pianificare l'attività Lambda dall'interno del flusso di lavoro.

### Configurazione di un ruolo IAM
<a name="set-up-lambda-role"></a>

Prima di poter richiamare le funzioni Lambda da Amazon SWF, devi fornire un ruolo IAM che fornisca l'accesso a Lambda da Amazon SWF. Puoi eseguire una delle seguenti operazioni:
+ *scegli un ruolo predefinito, Ruolo, AWSLambda per autorizzare i flussi di lavoro a richiamare qualsiasi funzione Lambda associata al tuo account.*
+ definisci la tua politica e il ruolo associato per autorizzare i flussi di lavoro a richiamare particolari funzioni Lambda, specificate dai rispettivi Amazon Resource Names (). ARNs

#### Limita le autorizzazioni su un ruolo IAM
<a name="limit-iam-role-permissions"></a>

Puoi limitare le autorizzazioni su un ruolo IAM che fornisci ad Amazon SWF utilizzando `SourceArn` le chiavi `SourceAccount` e context nella tua policy di attendibilità delle risorse. Queste chiavi limitano l'utilizzo di una policy IAM in modo che venga utilizzata solo dalle esecuzioni di Amazon Simple Workflow Service che appartengono all'ARN del dominio specificato. Se utilizzi entrambe le chiavi di contesto della condizione globale, il `aws:SourceAccount` valore e l'account a cui si fa riferimento nel `aws:SourceArn` valore devono utilizzare lo stesso ID account quando vengono utilizzati nella stessa dichiarazione politica.

Nel seguente esempio, la chiave di `SourceArn` contesto limita l'utilizzo del ruolo del servizio IAM solo nelle esecuzioni di Amazon Simple Workflow Service che appartengono `someDomain` all'account,. `123456789012`


+ **Dichiarazione 1**

  **Preside**: `"Service": "swf.amazonaws.com"` 

  **Operazione:** `sts:AssumeRole` 

```
"Condition": {
   "ArnLike": {
     "aws:SourceArn": "arn:aws:swf:*:123456789012:/domain/someDomain"
   }
}
```

Nell'esempio seguente, la chiave di `SourceAccount` contesto limita l'utilizzo del ruolo del servizio IAM solo nelle esecuzioni di Amazon Simple Workflow Service nell'account,. `123456789012`

```
"Condition": {
   "StringLike": {
     "aws:SourceAccount": "123456789012"
   }
}
```

#### Fornire ad Amazon SWF l'accesso per richiamare qualsiasi ruolo Lambda
<a name="providing-swf-access-invoke-any-lambda-role"></a>

Puoi utilizzare il ruolo predefinito, Role, per dare ai flussi di lavoro Amazon SWF la possibilità di richiamare qualsiasi *AWSLambdafunzione* Lambda associata al tuo account.

**Utilizzare AWSLambda Role per consentire ad Amazon SWF l'accesso per richiamare le funzioni Lambda**

1. Apri la [console Amazon IAM](https://console.aws.amazon.com/iam/).

1. Scegli **Roles** (Ruoli), quindi **Create New Role** (Crea nuovo ruolo).

1. Assegna un nome al ruolo, come `swf-lambda`, quindi scegli **Next Step** (Fase successiva).

1. In **AWS Service Roles**, scegli **Amazon SWF** e scegli **Next** Step.

1. Nella schermata **Allach Policy**, scegli **AWSLambdaRuolo** dall'elenco.

1. Scegli **Next Step** (Fase successiva), quindi **Create Role** (Crea ruolo) dopo aver esaminato il ruolo.

#### Definizione di un ruolo IAM per fornire l'accesso per richiamare una funzione Lambda specifica
<a name="defining-iam-role-provide-access-invoke-specific-lambda-function"></a>

Se desideri fornire l'accesso per richiamare una funzione Lambda specifica dal tuo flusso di lavoro, dovrai definire la tua policy IAM.

**Creare una policy IAM per fornire l'accesso a una particolare funzione Lambda**

1. Apri la [console Amazon IAM](https://console.aws.amazon.com/iam/).

1. Scegli **Policies** (Policy), quindi **Create Policy** (Crea policy).

1. Scegli **Copia una policy AWS gestita** e seleziona **AWSLambdaRuolo** dall'elenco. Viene generata una policy. Se necessario, modificane il nome e la descrizione.

1. Nel campo *Resource* del **Policy Document**, aggiungi l'ARN delle tue funzioni Lambda. Per esempio:
   + **Risorsa:** `arn:aws:lambda:us-east-1:111122223333:function:hello_lambda_function` 
**Nota**  
Per una descrizione completa di come specificare le risorse in un ruolo IAM, consulta [Panoramica delle politiche IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/policies_overview.html) nell'*uso* di IAM.

1. Scegli **Create Policy** (Crea policy) per completare la creazione della policy.

Puoi quindi selezionare questa policy quando crei un nuovo ruolo IAM e utilizzarlo per concedere a invoke l'accesso ai tuoi flussi di lavoro Amazon SWF. Questa procedura è molto simile alla creazione di un ruolo con la politica *AWSLambdaRole*. Scegli invece la tua policy quando crei il ruolo.

**Per creare un ruolo Amazon SWF utilizzando la tua policy Lambda**

1. Apri la [console Amazon IAM](https://console.aws.amazon.com/iam/).

1. Scegli **Roles** (Ruoli), quindi **Create New Role** (Crea nuovo ruolo).

1. Assegna un nome al ruolo, come `swf-lambda-function`, quindi scegli **Next Step** (Fase successiva).

1. In **AWS Service Roles**, scegli **Amazon SWF** e scegli **Next** Step.

1. Nella schermata **Allega policy**, scegli la policy specifica per la funzione Lambda dall'elenco.

1. Scegli **Next Step** (Fase successiva), quindi **Create Role** (Crea ruolo) dopo aver esaminato il ruolo.

### Pianifica l'esecuzione di un'attività Lambda
<a name="schedule-lambda-tasks-for-execution"></a>

Dopo aver definito un ruolo IAM che ti consente di richiamare le funzioni Lambda, puoi pianificarne l'esecuzione come parte del tuo flusso di lavoro.

**Nota**  
Questo processo è ampiamente dimostrato dall'[HelloLambda esempio](#see-lambda-sample) contenuto in. AWS SDK per Java

**Per pianificare l'esecuzione di un'attività Lambda**

1. Nell'implementazione di flusso di lavoro, ottieni un'istanza di `LambdaFunctionClient` chiamando `getLambdaFunctionClient()` su un'istanza `DecisionContext`.

   ```
   // Get a LambdaFunctionClient instance
   DecisionContextProvider decisionProvider = new DecisionContextProviderImpl();
   DecisionContext decisionContext = decisionProvider.getDecisionContext();
   LambdaFunctionClient lambdaClient = decisionContext.getLambdaFunctionClient();
   ```

1. Pianifica l'attività utilizzando il `scheduleLambdaFunction()` metodo su`LambdaFunctionClient`, passandole il nome della funzione Lambda che hai creato e tutti i dati di input per l'attività Lambda.

   ```
   // Schedule the Lambda function for execution, using your IAM role for access.
   String lambda_function_name = "The name of your Lambda function.";
   String lambda_function_input = "Input data for your Lambda task.";
   
   lambdaClient.scheduleLambdaFunction(lambda_function_name, lambda_function_input);
   ```

1. Nel programma di avvio dell'esecuzione del workflow, aggiungi il ruolo IAM lambda alle opzioni di workflow predefinite utilizzando`StartWorkflowOptions.withLambdaRole()`, quindi passa le opzioni all'avvio del flusso di lavoro.

   ```
   // Workflow client classes are generated for you when you use the @Workflow
   // annotation on your workflow interface declaration.
   MyWorkflowClientExternalFactory clientFactory =
     new MyWorkflowClientExternalFactoryImpl(sdk_swf_client, swf_domain);
   
   MyWorkflowClientExternal workflow_client = clientFactory.getClient();
   
   // Give the ARN of an IAM role that allows SWF to invoke Lambda functions on
   // your behalf.
   String lambda_iam_role = "arn:aws:iam::111111000000:role/swf_lambda_role";
   
   StartWorkflowOptions workflow_options =
     new StartWorkflowOptions().withLambdaRole(lambda_iam_role);
   
   // Start the workflow execution
   workflow_client.helloWorld("User", workflow_options);
   ```

## Visualizza l'esempio HelloLambda
<a name="see-lambda-sample"></a>

Un esempio che fornisce un'implementazione di un flusso di lavoro che utilizza un'attività Lambda è fornito in. AWS SDK per Java Per visualizzarlo, and/or eseguilo, [scarica il codice sorgente](https://aws.amazon.com/code/3015904745387737).

Una descrizione completa di come creare ed eseguire l'*HelloLambda*esempio è fornita nel file README fornito con AWS Flow Framework gli esempi Java.

# Esecuzione di programmi scritti con AWS Flow Framework for Java
<a name="running"></a>

**Topics**
+ [WorkflowWorker](#running.workflowworker)
+ [ActivityWorker](#running.activityworker)
+ [Modello di threading di lavoratore](#running.threadingmodel)
+ [Estensibilità dei lavoratori](#running.workerextend)

Il framework fornisce *classi di lavoro* per inizializzare il runtime AWS Flow Framework for Java e comunicare con Amazon SWF. Per implementare un lavoratore di attività o di flusso di lavoro, devi creare e avviare un'istanza di una classe di lavoratore. Queste classi di lavoratori sono responsabili della gestione delle operazioni asincrone in corso, dell'utilizzo di metodi asincroni che vengono sbloccati e della comunicazione con Amazon SWF. Possono essere configurate con implementazioni di flusso di lavoro e attività, il numero di thread, l'elenco di task da sottoporre a polling e così via. 

Il framework include due classi di lavoratore, una per le attività e l'altra per i flussi di lavoro. Per eseguire la logica di flusso di lavoro, devi utilizzare la classe `WorkflowWorker`. Per le attività, viene invece utilizzata la classe `ActivityWorker`. Queste classi eseguono automaticamente il polling di Amazon SWF per le attività e richiamano i metodi appropriati nella tua implementazione. 

L'esempio seguente mostra come creare un'istanza di `WorkflowWorker` e avviare il polling dei task: 

```
AmazonSimpleWorkflow swfClient = new AmazonSimpleWorkflowClient(awsCredentials);
WorkflowWorker worker = new WorkflowWorker(swfClient, "domain1", "tasklist1");
// Add workflow implementation types
worker.addWorkflowImplementationType(MyWorkflowImpl.class);

// Start worker
worker.start();
```

La procedura di base per creare un'istanza di `ActivityWorker` e avviare il polling dei task è la seguente:

```
AmazonSimpleWorkflow swfClient
      = new AmazonSimpleWorkflowClient(awsCredentials);
ActivityWorker worker = new ActivityWorker(swfClient,
                                           "domain1",
                                           "tasklist1");
worker.addActivitiesImplementation(new MyActivitiesImpl());

// Start worker
worker.start();
```

Quando desideri chiudere un'attività o un dispositivo decisionale, l'applicazione deve chiudere le istanze delle classi di lavoro utilizzate e l'istanza del client Java Amazon SWF. In questo modo, tutte le risorse utilizzate dalle classi di lavoratore vengono rilasciate correttamente.

```
worker.shutdown();
worker.awaitTermination(1, TimeUnit.MINUTES);
```

Per avviare un'esecuzione, crea semplicemente un'istanza del client esterno generato e chiama il metodo `@Execute`.

```
MyWorkflowClientExternalFactory factory = new MyWorkflowClientExternalFactoryImpl();
MyWorkflowClientExternal client = factory.getClient();
client.start();
```

## WorkflowWorker
<a name="running.workflowworker"></a>

Come suggerisce il nome, questa classe di lavoratore è utilizzata dall'implementazione di flusso di lavoro. È configurata con un elenco di task e con il tipo di implementazione di flusso di lavoro. La classe di lavoratore esegue un ciclo per il polling dei task di decisione nell'elenco di task specificato. Quando un task di decisione viene ricevuto, crea un'istanza dell'implementazione di flusso di lavoro e chiama il metodo `@Execute` per elaborare il task. 

## ActivityWorker
<a name="running.activityworker"></a>

Per implementare dei lavoratori di attività, puoi utilizzare la classe `ActivityWorker` per eseguire efficacemente il polling dei task di attività in un elenco di task. Configura quindi il lavoratore di attività con oggetti di implementazione di attività. Questa classe di lavoratore esegue un ciclo per il polling dei task di attività nell'elenco di task specificato. Quando si riceve un task di attività, cerca l'implementazione appropriata che hai fornito e chiama il metodo di attività per elaborare il task. A differenza di `WorkflowWorker`, che chiama la factory per creare una nuova istanza per ogni task di decisione, `ActivityWorker` utilizza semplicemente l'oggetto che hai fornito. 

La `ActivityWorker` classe utilizza le annotazioni AWS Flow Framework for Java per determinare le opzioni di registrazione ed esecuzione.

## Modello di threading di lavoratore
<a name="running.threadingmodel"></a>

In Java, AWS Flow Framework l'incarnazione di un'attività o di un decisore è un'istanza della classe operaia. La tua applicazione è responsabile della configurazione e della creazione di un'istanza dell'oggetto lavoratore su ogni macchina nonché del processo che agisce come lavoratore. L'oggetto worker riceve quindi automaticamente le attività da Amazon SWF, le invia all'implementazione dell'attività o del flusso di lavoro e riporta i risultati ad Amazon SWF. Una singola istanza di flusso di lavoro può interessare molti lavoratori. Quando Amazon SWF ha una o più attività in sospeso, assegna un'attività al primo lavoratore disponibile, quindi a quello successivo e così via. In questo modo, i task che appartengono alla stessa istanza di flusso di lavoro possono essere elaborati su differenti lavoratori contemporaneamente. 

![\[Topologia di quattro applicazioni basate su Java AWS Flow Framework\]](http://docs.aws.amazon.com/it_it/amazonswf/latest/awsflowguide/images/threading.png)


Inoltre, ogni lavoratore può essere configurato per elaborare task su più thread. Ciò significa che i task di attività di un'istanza di flusso di lavoro possono essere eseguiti simultaneamente anche se vi è un solo lavoratore. 

Le attività decisionali si comportano in modo simile, con l'eccezione che Amazon SWF garantisce che per un determinato flusso di lavoro possa essere eseguita solo una decisione alla volta. Una singola esecuzione di flusso di lavoro richiede in genere più task di decisione ed è quindi possibile che venga eseguita su più processi e thread. Il decisore è configurato con il tipo di implementazione di flusso di lavoro. Quando riceve un task di decisione, crea un'istanza (oggetto) dell'implementazione di flusso di lavoro. Il framework fornisce un modello factory estensibile per la creazione di queste istanze. La factory di flusso di lavoro di default crea un nuovo oggetto ogni volta. Puoi fornire factory personalizzate per annullare questo comportamento.

Contrariamente ai decisori, che sono configurati con tipi di implementazione di flusso di lavoro, i lavoratori di attività sono configurati con istanze (oggetti) delle implementazioni di attività. Quando un lavoratore di attività riceve un task di attività, questo è inviato all'oggetto di implementazione di attività appropriato. 

![\[Modello di threading delle classi di lavoratore\]](http://docs.aws.amazon.com/it_it/amazonswf/latest/awsflowguide/images/executor.png)


L'operatore del flusso di lavoro gestisce un unico pool di thread ed esegue il flusso di lavoro sullo stesso thread utilizzato per eseguire il polling di Amazon SWF per l'attività. Poiché le attività durano a lungo (almeno rispetto alla logica del flusso di lavoro), la classe Activity Worker gestisce due pool di thread separati: uno per il polling di Amazon SWF per le attività e l'altro per l'elaborazione delle attività eseguendo l'implementazione dell'attività. Ciò ti consente di configurare il numero di thread per il polling dei task indipendentemente dal numero di thread per eseguirli. Ad esempio, puoi avere un numero ridotto di thread per il polling e un numero elevato di thread per l'esecuzione dei task. L'activity worker class interroga Amazon SWF per un'attività solo quando dispone di un thread di sondaggio gratuito e di un thread libero per l'elaborazione dell'attività. 

Questo comportamento di threading e creazione di istanze implica quanto segue: 

1. Le implementazioni di attività devono essere stateless. Non devi utilizzare variabili di istanza per archiviare lo stato dell'applicazione in oggetti attività. Puoi comunque utilizzare dei campi per archiviare risorse come le connessioni di database.

1. Le implementazioni di attività devono essere thread-safe. Poiché la stessa istanza può essere utilizzata per elaborare attività da thread diversi contemporaneamente, l'accesso alle risorse condivise dal codice di attività deve essere sincronizzato.

1. L'implementazione di flusso di lavoro può essere stateful e le variabili di istanza possono essere utilizzate per archiviare lo stato. Anche se viene creata una nuova istanza dell'implementazione di flusso di lavoro per elaborare ogni task di decisione, il framework assicurerà la corretta ricreazione dello stato. Tuttavia, l'implementazione di flusso di lavoro deve essere deterministica. Per ulteriori informazioni, consulta la sezione [Comprensione di un task in AWS Flow Framework for Java](details.md).

1. Le implementazioni di flusso di lavoro non devono essere thread-safe quando si utilizza la factory di default. L'implementazione di default garantisce che un'istanza dell'implementazione di flusso di lavoro è utilizzata da un solo thread alla volta.

## Estensibilità dei lavoratori
<a name="running.workerextend"></a>

The AWS Flow Framework for Java contiene anche un paio di classi di lavoro di basso livello che offrono controllo ed estensibilità dettagliati. Mediante tali classi, puoi personalizzare completamente la registrazione dei tipi di flusso di lavoro e di attività e impostare factory per la creazione di oggetti di implementazione. Questi lavoratori sono `GenericWorkflowWorker` e `GenericActivityWorker`. 

Il lavoratore `GenericWorkflowWorker` può essere configurato con una factory per creare factory di definizione di flusso di lavoro. Il ruolo di una factory di definizione di flusso di lavoro è di creare istanze dell'implementazione di flusso di lavoro e di fornire impostazioni di configurazione come le opzioni di registrazione. In circostanze normali, devi utilizzare la classe `WorkflowWorker` direttamente. Questa creerà e configurerà automaticamente l'implementazione delle factory fornite nel framework, ovvero `POJOWorkflowDefinitionFactoryFactory` e `POJOWorkflowDefinitionFactory`. La factory richiede che la classe di implementazione di flusso di lavoro abbia un costruttore senza argomenti. Questo costruttore è utilizzato per creare istanze dell'oggetto di flusso di lavoro al runtime. La factory analizza le annotazioni utilizzate nell'interfaccia e nell'implementazione di flusso di lavoro per creare opzioni di registrazione ed esecuzione appropriate. 

Puoi fornire una tua implementazione delle factory mediante `WorkflowDefinitionFactory`, `WorkflowDefinitionFactoryFactory` e `WorkflowDefinition`. La classe `WorkflowDefinition` è utilizzata dalla classe di lavoratore per inviare task di decisione e segnali. Implementando queste classi di base, puoi personalizzare completamente la factory e l'invio di richieste all'implementazione di flusso di lavoro. Ad esempio, puoi utilizzare questi punti di estensibilità per fornire un modello di programmazione personalizzato per la scrittura di flussi di lavoro, ad esempio, basato sulle tue annotazioni o generato a partire da WSDL anziché mediante l'approccio Code First utilizzato dal framework. Per utilizzare le tue factory personalizzate, dovrai servirti della classe `GenericWorkflowWorker`. Per maggiori dettagli su queste classi, consulta la documentazione. AWS SDK per Java 

Allo stesso modo, `GenericActivityWorker` ti consente di fornire una factory di implementazione di attività personalizzata. Implementando le classi `ActivityImplementationFactory` e `ActivityImplementation`, puoi controllare completamente la creazione di istanze di attività nonché personalizzare opzioni di registrazione ed esecuzione. Per maggiori dettagli su queste classi, consulta la AWS SDK per Java documentazione.

# Contesto di esecuzione
<a name="executioncontext"></a>

**Topics**
+ [Contesto di decisione](#executioncontext.decision)
+ [Contesto di esecuzione di attività](#activitycontext)

Il framework fornisce un contesto di ambiente alle implementazioni di flusso di lavoro e attività. Questo contesto è specifico del task in corso di elaborazione e fornisce alcune utilità che puoi utilizzare nella tua implementazione. Un oggetto di contesto è creato ogni volta che il lavoratore elabora un nuovo task.

## Contesto di decisione
<a name="executioncontext.decision"></a>

Quando un'attività viene eseguita, la decisione quadro fornisce il contesto per l'implementazione di flussi di lavoro attraverso la `DecisionContext` classe `DecisionContext` fornisce informazioni sensibili al contesto quali l'esecuzione del flusso di lavoro eseguire Id e orologio timer e funzionalità.

### Accesso nell'implementazione del flusso DecisionContext di lavoro
<a name="executioncontext.decision.access"></a>

Puoi accedere a `DecisionContext` nell'implementazione di flusso di lavoro utilizzando la classe `DecisionContextProviderImpl`. In alternativa, puoi inserire il contesto in un campo o in una proprietà di tale implementazione utilizzando Spring come mostrato nella sezione relativa alla testabilità e all'inserimento delle dipendenze.

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

### Creazione di un orologio e di un timer
<a name="executioncontext.decision.timer"></a>

La classe `DecisionContext` contiene una proprietà di tipo `WorkflowClock` che fornisce la funzionalità di orologio e timer. Poiché la logica del flusso di lavoro deve essere deterministica, non è necessario utilizzare direttamente l'orologio di sistema nell'implementazione del flusso di lavoro. Il metodo `currentTimeMills` su `WorkflowClock` restituisce l'ora dell'evento di avvio della decisione in corso di elaborazione. In questo modo, ottieni lo stesso valore di ora durante la riproduzione, rendendo di conseguenza deterministica la logica di flusso di lavoro.

`WorkflowClock` include inoltre un metodo `createTimer` che restituisce un oggetto `Promise` che diventa pronto dopo l'intervallo specificato. Puoi utilizzare questo valore come parametro per altri metodi asincroni allo scopo di ritardarne l'esecuzione in base al periodo di tempo specificato. In questo modo, puoi pianificare efficacemente un'attività o un metodo asincrono per un'esecuzione successiva.

L'esempio nel listato seguente mostra come chiamare periodicamente un'attività.

```
@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() {
      ...
      }
}
```

Nel listato precedente, il metodo asincrono `callPeriodicActivity` chiama `activity1` e quindi crea un timer utilizzando la classe `AsyncDecisionContext` corrente. Passa l'oggetto `Promise` restituito come argomento a una chiamata ricorsiva a se stesso. Questa chiamata attende fino all'attivazione del timer (1 ora i questo esempio) prima dell'esecuzione.

## Contesto di esecuzione di attività
<a name="activitycontext"></a>

Esattamente come `DecisionContext` fornisce informazioni di contesto quando un task di decisione è in corso di elaborazione, `ActivityExecutionContext` fornisce informazioni di contesto simili durante l'elaborazione di un task di attività. Questo contesto è disponibile per il tuo codice delle attività mediante la classe `ActivityExecutionContextProviderImpl`.

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

Utilizzando `ActivityExecutionContext`, puoi eseguire le seguenti operazioni:

### Heartbeat di un'attività a esecuzione prolungata
<a name="activitycontext.heartbeat"></a>

Se l'attività è di lunga durata, deve segnalarne periodicamente l'avanzamento ad Amazon SWF per informarlo che l'attività sta ancora facendo progressi. In assenza di tale heartbeat, è possibile che si verifichi il timeout del task se un timeout di heartbeat è stato impostato alla registrazione del tipo di attività o durante la pianificazione dell'attività. Per inviare un heartbeat, puoi utilizzare il metodo `recordActivityHeartbeat` su `ActivityExecutionContext`. L'heartbeat fornisce inoltre un meccanismo per annullare le attività in corso. Per informazioni dettagliate e un esempio, consulta la sezione [Gestione errori](errorhandling.md).

### Ottenimento dei dettagli del task di attività
<a name="activitycontext.details"></a>

Se lo desideri, puoi ottenere tutti i dettagli dell'attività che sono stati trasmessi da Amazon SWF quando l'esecutore ha ricevuto l'attività. Sono incluse le informazioni relative agli input al task, il tipo di task, il token del task, ecc. Se desideri implementare un'attività che viene completata manualmente, ad esempio da un'azione umana, devi utilizzare il per recuperare il token dell'attività e passarlo `ActivityExecutionContext` al processo che alla fine completerà l'attività. Per ulteriori informazioni, consulta la sezione su [Completamento manuale della attività](activityimpl.md#activityimpl.complete).

### Ottieni l'oggetto client Amazon SWF utilizzato dall'esecutore
<a name="activitycontext.client"></a>

L'oggetto client Amazon SWF utilizzato dall'esecutore può essere recuperato chiamando method on. `getService` `ActivityExecutionContext` Ciò è utile se desideri effettuare una chiamata diretta al servizio Amazon SWF.

# Esecuzioni del flusso di lavoro figlio
<a name="childworkflow"></a>

Negli esempi riportati finora, abbiamo iniziato l'esecuzione del flusso di lavoro direttamente da un'applicazione. Tuttavia, un'esecuzione del flusso di lavoro può essere avviata dall'interno di un flusso di lavoro chiamando il metodo del punto di ingresso del flusso di lavoro sul client generato. Quando un'esecuzione del flusso di lavoro viene avviata dal contesto di un'altra esecuzione del flusso di lavoro viene chiamata esecuzione del flusso di lavoro figlio. Questa operazione ti permette di eseguire il refactoring dei flussi di lavoro complessi in unità più piccole e condividerle potenzialmente su diversi flussi di lavoro. Ad esempio, puoi creare un flusso di elaborazione dei pagamenti e chiamarlo da un flusso di lavoro di elaborazione di un ordine.

Da un punto di vista semantico, l'esecuzione del flusso di lavoro figlio si comporta analogamente al flusso di lavoro standalone tranne che per le seguenti caratteristiche:

1. Quando il flusso di lavoro principale termina a causa di un'azione esplicita da parte dell'utente, ad esempio chiamando l'API Amazon SWF`TerminateWorkflowExecution`, o viene interrotto a causa di un timeout, il destino dell'esecuzione del flusso di lavoro secondario sarà determinato da una policy secondaria. Puoi impostare la policy figlio in modo che termini, annulli o abbandoni (mantenere in esecuzione) le esecuzioni del flusso di lavoro figlio.

1. L'output del flusso di lavoro figlio (valore restituito del metodo del punto di ingresso) può essere utilizzato dall'esecuzione del flusso di lavoro padre come l'oggetto `Promise<T>` restituito da un metodo asincrono. Ciò è diverso dalle esecuzioni autonome in cui l'applicazione deve ottenere l'output utilizzando Amazon SWF. APIs

Nell'esempio seguente, il flusso di lavoro `OrderProcessor` crea un flusso di lavoro figlio `PaymentProcessor`:

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

    @Execute(version = "1.0")
    void processOrder(Order order);
}

public class OrderProcessorImpl implements OrderProcessor {
    PaymentProcessorClientFactory factory
         = new PaymentProcessorClientFactoryImpl();

    @Override
    public void processOrder(Order order) {
        float amount = order.getAmount();
        CardInfo cardInfo = order.getCardInfo();

        PaymentProcessorClient childWorkflowClient = factory.getClient();
        childWorkflowClient.processPayment(amount, cardInfo);
    }

}

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

    @Execute(version = "1.0")
    void processPayment(float amount, CardInfo cardInfo);

}

public class PaymentProcessorImpl implements PaymentProcessor {
    PaymentActivitiesClient activitiesClient = new PaymentActivitiesClientImpl();

    @Override
    public void processPayment(float amount, CardInfo cardInfo) {
        Promise<PaymentType> payType = activitiesClient.getPaymentType(cardInfo);
        switch(payType.get()) {
        case Visa:
            activitiesClient.processVisa(amount, cardInfo);
            break;
        case Amex:
            activitiesClient.processAmex(amount, cardInfo);
            break;
      default:
         throw new UnSupportedPaymentTypeException();
        }
    }

}

@Activities(version = "1.0")
@ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 3600,
                             defaultTaskStartToCloseTimeoutSeconds = 3600)
public interface PaymentActivities {

    PaymentType getPaymentType(CardInfo cardInfo);

    void processVisa(float amount, CardInfo cardInfo);

    void processAmex(float amount, CardInfo cardInfo);

}
```

# Flussi di lavoro continui
<a name="continuous"></a>

In alcuni casi d'uso, può servire un flusso di lavoro di durata lunga o eterna, ad esempio uno che monitori l'integrità di una flotta di server. 

**Nota**  
Poiché Amazon SWF conserva l'intera cronologia dell'esecuzione di un flusso di lavoro, la cronologia continuerà a crescere nel tempo. Il framework recupera la cronologia da Amazon SWF quando esegue una riproduzione; questo può diventare costoso se le dimensioni della cronologia sono troppo grandi. Nei flussi di lavoro di lunga durata o continui, devi chiudere periodicamente l'esecuzione in corso e avviarne una nuova per poter proseguire. 

 Questo è un proseguimento logico dell'esecuzione del flusso di lavoro. A questo scopo si può usare un self client generato. Nell'implementazione del flusso di lavoro, basta chiamare il metodo `@Execute` sul self client. Una volta completata l'esecuzione corrente, il framework avvia una nuova esecuzione utilizzando lo stesso ID del flusso di lavoro.

Puoi anche proseguire l'esecuzione chiamando il metodo `continueAsNewOnCompletion` nel `GenericWorkflowClient` che puoi recuperare dal `DecisionContext` corrente. Ad esempio, la seguente implementazione del flusso di lavoro imposta un timer perché si attivi dopo un giorno e chiama il suo punto di ingresso per avviare una nuova esecuzione. 

```
public class ContinueAsNewWorkflowImpl implements ContinueAsNewWorkflow {

    private DecisionContextProvider contextProvider
         = new DecisionContextProviderImpl();

    private ContinueAsNewWorkflowSelfClient selfClient
         = new ContinueAsNewWorkflowSelfClientImpl();

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

    @Override
    public void startWorkflow() {
        Promise<Void> timer = clock.createTimer(86400);
        continueAsNew(timer);
    }

    @Asynchronous
    void continueAsNew(Promise<Void> timer) {
        selfClient.startWorkflow();
    }
}
```

Quando un flusso di lavoro si chiama ricorsivamente, il framework chiude il flusso di lavoro in corso al completamento dei task in sospeso e avvia una nuova esecuzione. Ricorda che fino a quando ci sono task in sospeso, l'esecuzione corrente non può essere chiusa. La nuova esecuzione non eredita automaticamente la cronologia o i dati da quella originale; se vuoi esportare qualche stato sulla nuova esecuzione, dovrai trasferirlo esplicitamente come input.

# Impostazione della priorità delle attività in Amazon SWF
<a name="programming-priority"></a>

Per impostazione predefinita, i task in un elenco di task sono consegnati in base alla relativa *ora di arrivo*. Per quanto possibile, i task pianificati per primi vengono eseguiti per primi. Impostando una priorità opzionale, puoi dare *priorità* a determinate attività: Amazon SWF cercherà di fornire attività con priorità più alta in un elenco di attività prima di quelle con priorità inferiore.

Puoi impostare priorità di task per flussi di lavoro e attività. La priorità di task di un flusso di lavoro non ha alcuna incidenza sulla priorità di task di attività che pianifica e nemmeno sui flussi di lavoro figlio che avvia. La priorità predefinita per un'attività o un flusso di lavoro viene impostata (da te o da Amazon SWF) durante la registrazione e la priorità dell'attività registrata viene sempre utilizzata a meno che non venga sostituita durante la pianificazione dell'attività o l'avvio di un'esecuzione del flusso di lavoro.

I valori della priorità di task possono andare da "-2147483648" a "2147483647", con i numeri più alti indicanti la priorità più elevata. Se non imposti la priorità di task per un'attività o un flusso di lavoro, verrà assegnata la priorità zero ("0").

**Topics**
+ [Impostazione della priorità di task per flussi di lavoro](#task-priority-workflows)
+ [Impostazione della priorità di task per attività](#task-priority-activities)

## Impostazione della priorità di task per flussi di lavoro
<a name="task-priority-workflows"></a>

Puoi impostare la priorità di task per un flusso di lavoro durante la registrazione o l'avvio dello stesso. La priorità di task impostata alla registrazione del flusso di lavoro è utilizzata come impostazione di default per qualsiasi esecuzione di flusso di lavoro di quel tipo, a meno che non venga sovrascritta all'avvio dell'esecuzione di flusso di lavoro.

Per registrare un tipo di flusso di lavoro con una priorità di attività predefinita, imposta l'*defaultTaskPriority*opzione in [WorkflowRegistrationOptions](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/annotations/WorkflowRegistrationOptions.html)quando lo dichiari:

```
@Workflow
@WorkflowRegistrationOptions(
    defaultTaskPriority = 10,
    defaultTaskStartToCloseTimeoutSeconds = 240)
public interface PriorityWorkflow
{
    @Execute(version = "1.0")
    void startWorkflow(int a);
}
```

Puoi anche impostare *taskPriority* per un flusso di lavoro quando avvii quest'ultimo, sovrascrivendo la priorità di task (di default) registrata.

```
StartWorkflowOptions priorityWorkflowOptions
    = new StartWorkflowOptions().withTaskPriority(10);

PriorityWorkflowClientExternalFactory cf
    = new PriorityWorkflowClientExternalFactoryImpl(swfService, domain);

priority_workflow_client = cf.getClient();

priority_workflow_client.startWorkflow(
        "Smith, John", priorityWorkflowOptions);
```

Puoi inoltre impostare la priorità di task all'avvio di un flusso di lavoro figlio o quando si continua un flusso di lavoro come nuovo. Ad esempio, è possibile impostare l'opzione *[ContinueAsNewWorkflowExecutionParameters](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/generic/ContinueAsNewWorkflowExecutionParameters.html)TaskPriority* in o in. [StartChildWorkflowExecutionParameters](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/generic/StartChildWorkflowExecutionParameters.html)

## Impostazione della priorità di task per attività
<a name="task-priority-activities"></a>

Puoi impostare la priorità di task per un attività durante la registrazione o la pianificazione della stessa. La priorità di task impostata quando si registra un tipo di attività è utilizzata come priorità di default all'esecuzione dell'attività, a meno che non venga sovrascritta quando si pianifica l'attività.

Per registrare un tipo di attività con una priorità di attività predefinita, imposta l'*defaultTaskPriority*opzione in [ActivityRegistrationOptions](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/annotations/ActivityRegistrationOptions.html)quando la dichiari:

```
@Activities(version = "1.0")
@ActivityRegistrationOptions(
    defaultTaskPriority = 10,
    defaultTaskStartToCloseTimeoutSeconds = 120)
public interface ImportantActivities {
    int doSomethingImportant();
}
```

Puoi anche impostare *taskPriority* per un'attività durante la pianificazione, sovrascrivendo la priorità di task (di default) registrata.

```
ActivitySchedulingOptions activityOptions = new ActivitySchedulingOptions.withTaskPriority(10);

ImportantActivitiesClient activityClient = new ImportantActivitiesClientImpl();

activityClient.doSomethingImportant(activityOptions);
```

# DataConverters
<a name="dataconverters"></a>

 Quando l'implementazione di flusso di lavoro chiama un'attività remota, l'input passato e il risultato dell'esecuzione dell'attività devono essere serializzati per essere trasmessi. Il framework utilizza la DataConverter classe per questo scopo. Si tratta di una classe astratta che puoi implementare per fornire un serializzatore personalizzato. Nel framework viene fornita un'implementazione predefinita basata sul serializzatore Jackson. `JsonDataConverter` Per ulteriori dettagli, consulta la [documentazione di AWS SDK per Java](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/JsonDataConverter.html). Fai riferimento alla documentazione del processore Jackson JSON per informazioni dettagliate sul modo in cui Jackson esegue la serializzazione e sulle annotazioni che possono essere utilizzate per modificarla. Il formato di trasmissione è considerato come parte del contratto. Di conseguenza, puoi specificare una classe `DataConverter` sulle interfacce di attività e di flusso di lavoro impostando la proprietà `DataConverter` delle annotazioni `@Activities` e `@Workflow`. 

Il framework creerà oggetti del tipo `DataConverter` specificato sull'annotazione `@Activities` per serializzare gli input all'attività e per deserializzarne il risultato. Analogamente, gli oggetti del tipo `DataConverter` specificato sull'annotazione `@Workflow` saranno utilizzati per serializzare i parametri che passi al flusso di lavoro e, nel caso di un flusso di lavoro figlio, per deserializzare il risultato. Oltre agli input, il framework trasmette anche dati aggiuntivi ad Amazon SWF, ad esempio i dettagli delle eccezioni, il serializzatore del flusso di lavoro verrà utilizzato anche per serializzare questi dati.

Puoi anche fornire un'istanza di `DataConverter` se non vuoi che venga creata automaticamente dal framework. I client generati hanno overload di costruttore che accettano un oggetto `DataConverter`.

Se non specifichi un tipo di `DataConverter` e non passi un oggetto `DataConverter`, `JsonDataConverter` sarà utilizzato per impostazione predefinita.

# Passaggio di dati a metodi asincroni
<a name="advanceddatapassing"></a>

**Topics**
+ [Passaggio di raccolte e mappe a metodi asincroni](#advanceddatapassing.collections)
+ [impostabile <T>](#advanceddatapassing.settable)
+ [@NoWait](#advanceddatapassing.nowait)
+ [Promise <Void>](#advanceddatapassing.promise)
+ [AndPromise e OrPromise](#advanceddatapassing.andorpromise)

L'utilizzo di `Promise<T>` è stato descritto nelle sezioni precedenti. In questa, vengono presentati alcuni casi d'uso avanzati di `Promise<T>`.

## Passaggio di raccolte e mappe a metodi asincroni
<a name="advanceddatapassing.collections"></a>

Il framework supporta il passaggio di matrici, raccolte e mappe come tipi `Promise` a metodi asincroni. Ad esempio, un metodo asincrono può accettare `Promise<ArrayList<String>>` come argomento come mostrato nel listato seguente.

```
@Asynchronous
public void printList(Promise<List<String>> list) {
    for (String s: list.get()) {
        activityClient.printActivity(s);
    }
}
```

Sul piano semantico, il comportamento è quello di qualsiasi altro parametro di tipo `Promise` e il metodo asincrono attenderà fino a che la raccolta diventa disponibile prima di avviare l'esecuzione. Se i membri di una raccolta sono oggetti `Promise`, il framework può attendere che tutti i membri diventino pronti come mostrato nel frammento seguente. In questo modo, il metodo asincrono attende che ogni membro della raccolta diventi disponibile.

```
@Asynchronous
public void printList(@Wait List<Promise<String>> list) {
  for (Promise<String> s: list) {
      activityClient.printActivity(s);
  }
}
```

 Nota che l'annotazione `@Wait` deve essere utilizzata nel parametro per indicare che contiene oggetti `Promise`. 

 Considera inoltre che l'attività `printActivity` accetta un argomento `String` ma il metodo corrispondente nel client generato accetta Promise<String>. Stiamo chiamando il metodo sul client e non richiamando il metodo dell'attività direttamente. 

## impostabile <T>
<a name="advanceddatapassing.settable"></a>

`Settable<T>` è un tipo derivato di `Promise<T>` che fornisce un metodo set con cui impostare manualmente il valore di un oggetto `Promise`. Ad esempio, il seguente flusso di lavoro attende la ricezione di un segnale attendendo `Settable<?>`, impostato nel metodo del segnale:

```
public class MyWorkflowImpl implements MyWorkflow{
   final Settable<String> result = new Settable<String>();

   //@Execute method
   @Override
   public Promise<String> start() {
      return done(result);
   }

   //Signal
   @Override
   public void manualProcessCompletedSignal(String data) {
      result.set(data);
   }

   @Asynchronous
   public Promise<String> done(Settable<String> result){
       return result;
   }
}
```

`Settable<?>` può inoltre essere concatenato a un'altra promessa alla volta. Puoi utilizzare `AndPromise` e `OrPromise` per raggruppare le promesse. Puoi annullare la concatenazione di `Settable` chiamando il metodo `unchain()`. Quando concatenato, `Settable<?>` diventa automaticamente pronto quando la promessa a cui è concatenato diventa pronta. La concatenazione è particolarmente utile quando desideri utilizzare una promessa restituita dall'ambito di un metodo `doTry()` in altre parti del programma. Poiché `TryCatchFinally` viene utilizzata come classe annidata, non è possibile dichiarare una `Promise<>` nell'ambito del genitore e impostarla. `doTry()` Questo perché Java richiede variabili che devono essere dichiarate nell'ambito padre e utilizzate in classi nidificate per essere contrassegnate come final. Esempio:

```
@Asynchronous
public Promise<String> chain(final Promise<String> input) {
    final Settable<String> result = new Settable<String>();

    new TryFinally() {

        @Override
        protected void doTry() throws Throwable {
            Promise<String> resultToChain = activity1(input);
            activity2(resultToChain);

            // Chain the promise to Settable
            result.chain(resultToChain);
        }

        @Override
        protected void doFinally() throws Throwable {
            if (result.isReady()) { // Was a result returned before the exception?
                // Do cleanup here
            }
        }
    };

    return result;
}
```

`Settable` può essere concatenato a una promessa alla volta. Puoi annullare la concatenazione di `Settable` chiamando il metodo `unchain()`.

## @NoWait
<a name="advanceddatapassing.nowait"></a>

Quando passi un oggetto `Promise` a un metodo asincrono, per impostazione predefinita il framework attende che gli oggetti `Promise` diventino pronti prima di eseguire il metodo (ad eccezione dei tipi di raccolta). Puoi eseguire l'override di questo comportamento utilizzando l'annotazione `@NoWait` sui parametri nella dichiarazione del metodo asincrono. Ciò è utile se passi `Settable<T>`, che verrà impostato dal metodo asincrono stesso.

## Promise <Void>
<a name="advanceddatapassing.promise"></a>

Le dipendenze nei metodi asincroni sono implementate passando l'oggetto `Promise` restituito da un metodo come argomento a un altro metodo. Possono tuttavia esserci casi in cui vuoi che un metodo restituisca `void` e che altri metodi asincroni siano eseguiti dopo il completamento di quel metodo. Per quei casi, puoi utilizzare `Promise<Void>` come tipo restituito del metodo. La classe `Promise` fornisce un metodo `Void` statico che puoi utilizzare per creare un oggetto `Promise<Void>`. Questo oggetto `Promise` diventerà pronto al termine dell'esecuzione del metodo asincrono. Puoi passare questo oggetto `Promise` a un altro metodo asincrono come qualsiasi altro oggetto `Promise`. Se utilizzi `Settable<Void>`, chiama il metodo set con null per renderlo pronto.

## AndPromise e OrPromise
<a name="advanceddatapassing.andorpromise"></a>

`AndPromise` e `OrPromise` ti consentono di raggruppare molteplici oggetti `Promise<>` in un'unica promessa logica. Un oggetto `AndPromise` diventa pronto quanto tutte le promesse utilizzate per costruirlo diventano pronte. Un oggetto `OrPromise` diventa pronto quando qualsiasi promessa nella raccolta di promesse utilizzata per costruirla diventa pronta. Puoi chiamare `getValues()` su `AndPromise` e `OrPromise` per recuperare l'elenco di valori delle promesse costituenti.

# Testabilità e inserimento delle dipendenze
<a name="test"></a>

**Topics**
+ [Integrazione di Spring](#test.spring)
+ [JUnit Integrazione](#test.junit)

Il framework è progettato per essere compatibile con l'Inversione del controllo (Inversion of Control, IoC). Le implementazioni di flussi di lavoro e di attività, nonché i lavoratori e gli oggetti di contesto forniti dal framework, si possono configurare e creare come istanze tramite contenitori come Spring. Il framework offre un'integrazione immediata con Spring Framework. Inoltre, JUnit è stata fornita l'integrazione con per le implementazioni del flusso di lavoro e delle attività di unit testing. 

## Integrazione di Spring
<a name="test.spring"></a>

Il pacchetto com.amazonaws.services.simpleworkflow.flow.spring contiene classi che semplificano l'utilizzo di Spring framework nelle applicazioni. Comprendono lavoratori di flusso di lavoro e di attività compatibili con Scope e Spring: `WorkflowScope`, `SpringWorkflowWorker` e `SpringActivityWorker`. Queste classi ti permettono di configurare le implementazioni di attività e flusso di lavoro, nonché i lavoratori interamente tramite Spring.

### WorkflowScope
<a name="test.workflowscope"></a>

`WorkflowScope` è una implementazione in ambito Spring personalizzata fornita dal framework. Lo scope ti permette di creare oggetti nel contenitore Spring la cui durata è limitata a quella di un task di decisione. I bean nello scope sono creati come istanze ogni volta che un lavoratore riceve un task di decisione. Devi utilizzare questo scope per i bean di implementazione del flusso di lavoro e per ogni altro bean da cui dipende. Per i bean di implementazione del flusso di lavoro non si devono usare gli scopes singleton e prototype forniti da Spring, perché il framework richiede la creazione di un nuovo bean per ciascun task di decisione. In caso contrario si verifica un comportamento inatteso.

Il seguente esempio mostra un frammento di codice della configurazione Spring che registra il `WorkflowScope` e poi lo utilizza per configurare un bean di implementazione del flusso di lavoro e un bean di client dell'attività.

```
<!-- register AWS Flow Framework for Java WorkflowScope -->
   <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
      <property name="scopes">
       <map>
         <entry key="workflow">
          <bean class="com.amazonaws.services.simpleworkflow.flow.spring.WorkflowScope" />
         </entry>
       </map>
      </property>
   </bean>

   <!-- activities client -->
   <bean id="activitiesClient" class="aws.flow.sample.MyActivitiesClientImpl" scope="workflow">
   </bean>

   <!-- workflow implementation -->
   <bean id="workflowImpl" class="aws.flow.sample.MyWorkflowImpl" scope="workflow">
      <property name="client" ref="activitiesClient"/>
      <aop:scoped-proxy proxy-target-class="false" />
   </bean>
```

La riga di configurazione: `<aop:scoped-proxy proxy-target-class="false" />`, utilizzata nella configurazione del bean `workflowImpl`, è obbligatoria perché `WorkflowScope` non supporta il proxy tramite CGLIB. Devi utilizzare questa configurazione per tutti i bean in `WorkflowScope` collegati a un altro bean in uno scope diverso. In questo caso, il bean `workflowImpl` deve essere collegato a un bean del lavoratore di flusso di lavoro in scope singleton (vedi l'esempio completo in basso).

Puoi approfondire l'utilizzo degli scope personalizzati nella documentazione di Spring Framework.

### Lavoratori compatibili con Spring
<a name="test.springworkers"></a>

Quando usi Spring, devi utilizzare le classi di lavoratori compatibili con Spring fornite dal framework: `SpringWorkflowWorker` e `SpringActivityWorker`. Questi lavoratori possono essere inseriti in un'applicazione tramite Spring, come illustrato nel prossimo esempio. I lavoratori compatibili con Spring implementano l'interfaccia `SmartLifecycle` di Spring e per impostazione predefinita iniziano automaticamente a eseguire il polling dei task quando viene avviato il contesto Spring. Puoi disattivare questa funzionalità impostando la proprietà `disableAutoStartup` del lavoratore su `true`.

L'esempio seguente mostra come configurare un decisore. Questo esempio utilizza le interfacce `MyActivities` e `MyWorkflow` (non mostrate qui) e le relative implementazioni, `MyActivitiesImpl` e `MyWorkflowImpl`. Le interfacce client e le implementazioni generate sono `MyWorkflowClient`/`MyWorkflowClientImpl` e `MyActivitiesClient`/`MyActivitiesClientImpl` (anch'esse non mostrate qui).

Il client delle attività viene introdotto nell'implementazione del flusso di lavoro utilizzando la funzionalità di collegamento automatico di Spring:

```
public class MyWorkflowImpl implements MyWorkflow {
   @Autowired
   public MyActivitiesClient client;

   @Override
   public void start() {
      client.activity1();
   }
}
```

La configurazione Spring per il decisore è la seguente:

```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
   http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <!-- register custom workflow scope -->
   <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
      <property name="scopes">
       <map>
         <entry key="workflow">
          <bean class="com.amazonaws.services.simpleworkflow.flow.spring.WorkflowScope" />
         </entry>
       </map>
      </property>
   </bean>
   <context:annotation-config/>

   <bean id="accesskeys" class="com.amazonaws.auth.BasicAWSCredentials">
      <constructor-arg value="{AWS.Access.ID}"/>
      <constructor-arg value="{AWS.Secret.Key}"/>
   </bean>

   <bean id="clientConfiguration" class="com.amazonaws.ClientConfiguration">
      <property name="socketTimeout" value="70000" />
   </bean>

   <!-- Amazon SWF client -->
   <bean id="swfClient"
      class="com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient">
      <constructor-arg ref="accesskeys" />
      <constructor-arg ref="clientConfiguration" />
      <property name="endpoint" value="{service.url}" />
   </bean>

   <!-- activities client -->
   <bean id="activitiesClient" class="aws.flow.sample.MyActivitiesClientImpl" scope="workflow">
   </bean>

   <!-- workflow implementation -->
   <bean id="workflowImpl" class="aws.flow.sample.MyWorkflowImpl" scope="workflow">
      <property name="client" ref="activitiesClient"/>
      <aop:scoped-proxy proxy-target-class="false" />
   </bean>

   <!-- workflow worker -->
   <bean id="workflowWorker"
      class="com.amazonaws.services.simpleworkflow.flow.spring.SpringWorkflowWorker">
      <constructor-arg ref="swfClient" />
      <constructor-arg value="domain1" />
      <constructor-arg value="tasklist1" />
      <property name="registerDomain" value="true" />
      <property name="domainRetentionPeriodInDays" value="1" />
      <property name="workflowImplementations">
         <list>
            <ref bean="workflowImpl" />
         </list>
      </property>
   </bean>
</beans>
```

Poiché `SpringWorkflowWorker` è completamente configurato in Spring e avvia automaticamente il polling quando il contesto Spring viene inizializzato, il processo host per il decisore è semplice:

```
public class WorkflowHost {
   public static void main(String[] args){
      ApplicationContext context
          = new FileSystemXmlApplicationContext("resources/spring/WorkflowHostBean.xml");
      System.out.println("Workflow worker started");
   }
}
```

Analogamente, il lavoratore di attività può essere configurato nel modo seguente:

```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
   http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <!-- register custom scope -->
   <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
      <property name="scopes">
         <map>
            <entry key="workflow">
               <bean
                  class="com.amazonaws.services.simpleworkflow.flow.spring.WorkflowScope" />
            </entry>
         </map>
      </property>
   </bean>

   <bean id="accesskeys" class="com.amazonaws.auth.BasicAWSCredentials">
      <constructor-arg value="{AWS.Access.ID}"/>
      <constructor-arg value="{AWS.Secret.Key}"/>
   </bean>

   <bean id="clientConfiguration" class="com.amazonaws.ClientConfiguration">
      <property name="socketTimeout" value="70000" />
   </bean>

   <!-- Amazon SWF client -->
   <bean id="swfClient"
      class="com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient">
      <constructor-arg ref="accesskeys" />
      <constructor-arg ref="clientConfiguration" />
      <property name="endpoint" value="{service.url}" />
   </bean>

   <!-- activities impl -->
   <bean name="activitiesImpl" class="asadj.spring.test.MyActivitiesImpl">
   </bean>

   <!-- activity worker -->
   <bean id="activityWorker"
      class="com.amazonaws.services.simpleworkflow.flow.spring.SpringActivityWorker">
      <constructor-arg ref="swfClient" />
      <constructor-arg value="domain1" />
      <constructor-arg value="tasklist1" />
      <property name="registerDomain" value="true" />
      <property name="domainRetentionPeriodInDays" value="1" />
      <property name="activitiesImplementations">
         <list>
            <ref bean="activitiesImpl" />
         </list>
      </property>
   </bean>
</beans>
```

Il processo di hosting del lavoratore di attività è simile a quello del decisore:

```
public class ActivityHost {
   public static void main(String[] args) {
      ApplicationContext context = new FileSystemXmlApplicationContext(
      "resources/spring/ActivityHostBean.xml");
      System.out.println("Activity worker started");
   }
}
```

### Contesto di decisione dell'introduzione
<a name="test.injectdecision"></a>

Se l'implementazione del flusso di lavoro dipende dagli oggetti del contesto, puoi introdurli facilmente utilizzando Spring come nel caso precedente. Il framework registra automaticamente i bean relativi al contesto nel contenitore Spring. Ad esempio, nel frammento di codice seguente, i diversi oggetti del contesto sono stati collegati automaticamente. Non è richiesta nessun'altra configurazione Spring degli oggetti del contesto.

```
public class MyWorkflowImpl implements MyWorkflow {
   @Autowired
   public MyActivitiesClient client;
   @Autowired
   public WorkflowClock clock;
   @Autowired
   public DecisionContext dcContext;
   @Autowired
   public GenericActivityClient activityClient;
   @Autowired
   public GenericWorkflowClient workflowClient;
   @Autowired
   public WorkflowContext wfContext;
   @Override
   public void start() {
      client.activity1();
   }
}
```

Se vuoi configurare gli oggetti del contesto nell'implementazione del flusso di lavoro tramite la configurazione Spring XML, utilizza i nomi di bean dichiarati nella classe `WorkflowScopeBeanNames` del pacchetto com.amazonaws.services.simpleworkflow.flow.spring. Per esempio:

```
<!-- workflow implementation -->
<bean id="workflowImpl" class="asadj.spring.test.MyWorkflowImpl" scope="workflow">
   <property name="client" ref="activitiesClient"/>
   <property name="clock" ref="workflowClock"/>
   <property name="activityClient" ref="genericActivityClient"/>
   <property name="dcContext" ref="decisionContext"/>
   <property name="workflowClient" ref="genericWorkflowClient"/>
   <property name="wfContext" ref="workflowContext"/>
   <aop:scoped-proxy proxy-target-class="false" />
</bean>
```

In alternativa, puoi introdurre un `DecisionContextProvider` nel bean di implementazione del flusso di lavoro e utilizzarlo per creare il contesto. Può essere utile se vuoi fornire implementazioni personalizzate del provider e del contesto.

### Introdurre le risorse nelle attività
<a name="test.injectresource"></a>

Puoi creare come istanze e configurare implementazioni di attività utilizzando un contenitore di inversione di controllo (Inversion of Control, IoC) e introdurre facilmente risorse, come le connessioni di database, dichiarandole come proprietà della classe di implementazione delle attività. Queste risorse verranno in genere assegnate come singleton. Ricorda che le implementazioni di attività sono chiamate dal lavoratore su più thread. Di conseguenza, l'accesso alle risorse condivise deve essere sincronizzato.

## JUnit Integrazione
<a name="test.junit"></a>

Il framework fornisce JUnit estensioni e implementazioni di test degli oggetti di contesto, come un orologio di test, che è possibile utilizzare per scrivere ed eseguire test unitari. JUnit Con queste estensioni, puoi testare localmente e inline l'implementazione del flusso di lavoro.

### Scrivere un semplice unit test
<a name="test.junit.simple"></a>

 Per scrivere test per il flusso di lavoro, utilizza la classe `WorkflowTest` nel pacchetto com.amazonaws.services.simpleworkflow.flow.junit. Questa classe è un' JUnit `MethodRule`implementazione specifica del framework ed esegue il codice del flusso di lavoro localmente, chiamando le attività in linea anziché tramite Amazon SWF. Questo ti dà la flessibilità per eseguire i test con la frequenza che preferisci senza alcun addebito. 

Per utilizzare questa classe, dichiara semplicemente un campo di tipo `WorkflowTest` e arricchiscilo con l'annotazione `@Rule`. Prima di eseguire i test, crea un nuovo oggetto `WorkflowTest` e aggiungi ad esso le implementazioni di attività e del flusso di lavoro. Puoi utilizzare la client factory del flusso di lavoro generata per creare un client e avviare un'esecuzione del flusso di lavoro. Il framework fornisce anche un JUnit runner personalizzato, `FlowBlockJUnit4ClassRunner` da utilizzare per i test del flusso di lavoro. Per esempio: 

```
@RunWith(FlowBlockJUnit4ClassRunner.class)
public class BookingWorkflowTest {

    @Rule
    public WorkflowTest workflowTest = new WorkflowTest();

    List<String> trace;

    private BookingWorkflowClientFactory workflowFactory
         = new BookingWorkflowClientFactoryImpl();

    @Before
    public void setUp() throws Exception {
        trace = new ArrayList<String>();
        // Register activity implementation to be used during test run
        BookingActivities activities = new BookingActivitiesImpl(trace);
        workflowTest.addActivitiesImplementation(activities);
        workflowTest.addWorkflowImplementationType(BookingWorkflowImpl.class);
    }

    @After
    public void tearDown() throws Exception {
        trace = null;
    }

    @Test
    public void testReserveBoth() {
        BookingWorkflowClient workflow = workflowFactory.getClient();
        Promise<Void> booked = workflow.makeBooking(123, 345, true, true);
        List<String> expected = new ArrayList<String>();
        expected.add("reserveCar-123");
        expected.add("reserveAirline-123");
        expected.add("sendConfirmation-345");
        AsyncAssert.assertEqualsWaitFor("invalid booking", expected, trace, booked);
    }
}
```

Puoi anche specificare un elenco separato di task per ciascuna implementazione di attività aggiunta a `WorkflowTest`. Ad esempio, se hai un'implementazione del flusso di lavoro che pianifica attività in elenchi di task specifici dell'host, puoi registrare l'attività nell'elenco di task di ciascun host:

```
for (int i = 0; i < 10; i++) {
    String hostname = "host" + i;
    workflowTest.addActivitiesImplementation(hostname,
                                             new ImageProcessingActivities(hostname));
}
```

Tieni presente che il codice in `@Test` è asincrono. Devi quindi utilizzare il client di flusso di lavoro asincrono per avviare un'esecuzione. Per verificare i risultati dei test, viene anche fornita una classe di aiuto `AsyncAssert`. Questa classe ti permette di attendere che le promesse siano pronte prima di verificare i risultati. In questo esempio, attendiamo che sia pronto il risultato dell'esecuzione del flusso di lavoro prima di verificare l'output del test.

Se utilizzi Spring, si può usare la classe `SpringWorkflowTest` invece di quella `WorkflowTest`. `SpringWorkflowTest` fornisce proprietà che puoi utilizzare per configurare facilmente le implementazioni di attività e di flusso di lavoro tramite la configurazione di Spring. Esattamente come per i lavoratori compatibili con Spring, devi utilizzare `WorkflowScope` per configurare i bean di implementazione del flusso di lavoro. In questo modo siamo sicuri che venga creato un nuovo bean di implementazione del flusso di lavoro per ogni task di decisione. Assicurati di configurare questi bean con l'impostazione scoped-proxy proxy-target-class impostata su. `false` Consulta la sezione Integrazione di Spring per maggiori dettagli. La configurazione Spring di esempio mostrata nella sezione Integrazione di Spring può essere modificata per testare il flusso di lavoro utilizzando `SpringWorkflowTest`: 

```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans ht
tp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframe
work.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <!-- register custom workflow scope -->
  <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
      <map>
        <entry key="workflow">
          <bean
            class="com.amazonaws.services.simpleworkflow.flow.spring.WorkflowScope" />
        </entry>
      </map>
    </property>
  </bean>
  <context:annotation-config />
  <bean id="accesskeys" class="com.amazonaws.auth.BasicAWSCredentials">
    <constructor-arg value="{AWS.Access.ID}" />
    <constructor-arg value="{AWS.Secret.Key}" />
  </bean>
  <bean id="clientConfiguration" class="com.amazonaws.ClientConfiguration">
    <property name="socketTimeout" value="70000" />
  </bean>

  <!-- Amazon SWF client -->
  <bean id="swfClient"
    class="com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient">
    <constructor-arg ref="accesskeys" />
    <constructor-arg ref="clientConfiguration" />
    <property name="endpoint" value="{service.url}" />
  </bean>

  <!-- activities client -->
  <bean id="activitiesClient" class="aws.flow.sample.MyActivitiesClientImpl"
    scope="workflow">
  </bean>

  <!-- workflow implementation -->
  <bean id="workflowImpl" class="aws.flow.sample.MyWorkflowImpl"
    scope="workflow">
    <property name="client" ref="activitiesClient" />
    <aop:scoped-proxy proxy-target-class="false" />
  </bean>

  <!-- WorkflowTest -->
  <bean id="workflowTest"
    class="com.amazonaws.services.simpleworkflow.flow.junit.spring.SpringWorkflowTest">
    <property name="workflowImplementations">
      <list>
        <ref bean="workflowImpl" />
      </list>
    </property>
    <property name="taskListActivitiesImplementationMap">
      <map>
        <entry>
          <key>
            <value>list1</value>
          </key>
          <ref bean="activitiesImplHost1" />
        </entry>
      </map>
    </property>
  </bean>
</beans>
```

#### Implementazioni di attività fittizie
<a name="test.junit.mockactivity"></a>

Durante i test puoi usare implementazioni di attività reali, ma se vuoi eseguire unit test solo della logica del flusso di lavoro, puoi simulare le attività. Questo avviene fornendo un'implementazione fittizia dell'interfaccia delle attività alla classe `WorkflowTest`. Per esempio: 

```
@RunWith(FlowBlockJUnit4ClassRunner.class)
public class BookingWorkflowTest {

    @Rule
    public WorkflowTest workflowTest = new WorkflowTest();

    List<String> trace;

    private BookingWorkflowClientFactory workflowFactory
         = new BookingWorkflowClientFactoryImpl();

    @Before
    public void setUp() throws Exception {
        trace = new ArrayList<String>();
        // Create and register mock activity implementation to be used during test run
        BookingActivities activities = new BookingActivities() {

            @Override
            public void sendConfirmationActivity(int customerId) {
                trace.add("sendConfirmation-" + customerId);
            }

            @Override
            public void reserveCar(int requestId) {
                trace.add("reserveCar-" + requestId);
            }

            @Override
            public void reserveAirline(int requestId) {
                trace.add("reserveAirline-" + requestId);
            }
        };
        workflowTest.addActivitiesImplementation(activities);
        workflowTest.addWorkflowImplementationType(BookingWorkflowImpl.class);
    }

    @After
    public void tearDown() throws Exception {
        trace = null;
    }

    @Test
    public void testReserveBoth() {
        BookingWorkflowClient workflow = workflowFactory.getClient();
        Promise<Void> booked = workflow.makeBooking(123, 345, true, true);
        List<String> expected = new ArrayList<String>();
        expected.add("reserveCar-123");
        expected.add("reserveAirline-123");
        expected.add("sendConfirmation-345");
        AsyncAssert.assertEqualsWaitFor("invalid booking", expected, trace, booked);
    }
}
```

In alternativa, puoi fornire un'implementazione fittizia del client delle attività e introdurla nell'implementazione del flusso di lavoro.

### Testare gli oggetti contesto
<a name="test.junit.objects"></a>

Se l'implementazione del flusso di lavoro dipende dagli oggetti del contesto del framework, ad esempio, non `DecisionContext` è necessario fare nulla di speciale per testare tali flussi di lavoro. Quando viene eseguito un test tramite `WorkflowTest`, questo introduce automaticamente oggetti contesto di test. Quando l'implementazione del flusso di lavoro accede agli oggetti di contesto, ad esempio utilizzando`DecisionContextProviderImpl`, otterrà l'implementazione di test. Puoi manipolare questi oggetti contesto di test nel codice di test (metodo `@Test`) per creare casi interessanti di test. Ad esempio, se il flusso di lavoro crea un timer, puoi attivarlo chiamando il metodo `clockAdvanceSeconds` nella classe `WorkflowTest` per muovere l'orologio in avanti. Puoi anche accelerare l'orologio per attivare i timer in anticipo rispetto al normale utilizzando la proprietà `ClockAccelerationCoefficient` su `WorkflowTest`. Ad esempio, se il flusso di lavoro crea un timer per un ora, puoi impostare `ClockAccelerationCoefficient` su 60 per attivare il timer in un minuto. Per impostazione predefinita, `ClockAccelerationCoefficient` è impostato su 1. 

Per ulteriori dettagli sui pacchetti com.amazonaws.services.simpleworkflow.flow.test e com.amazonaws.services.simpleworkflow.flow.junit, consulta la documentazione AWS SDK per Java . 

# Gestione errori
<a name="errorhandling"></a>

**Topics**
+ [TryCatchFinally Semantica](#errorhandling.trycatchfinally)
+ [Annullamento](#test.cancellation.resources)
+ [Annidato TryCatchFinally](#errorhandling.nested)

Il costrutto `try`/`catch`/`finally` in Java semplifica la gestione degli errori ed è quindi utilizzato diffusamente. Consente di associare gestori di errori a un blocco di codice. Internamente, ciò avviene aggiungendo ulteriori metadati sui gestori di errori allo stack di chiamate. Quando viene generata un'eccezione, il runtime cerca un gestore di errori associato nello stack di chiamate e lo richiama; se non lo trova, propaga l'eccezione fino alla catena di chiamate.

Questo processo è appropriato per il codice sincrono, ma la gestione degli errori in programmi distribuiti e asincroni è più complesso. Poiché una chiamata asincrona ritorna immediatamente, il chiamante non è presente nello stack di chiamate quando viene eseguito il codice asincrono. Ciò significa che le eccezioni non gestite nel codice asincrono non possono essere gestite dal chiamante nel modo usuale. In genere, le eccezioni generate nel codice asincrono sono gestite passando lo stato di errore a un callback che viene passato a un metodo asincrono. Se in alternativa si utilizza `Future<?>`, viene restituito un errore quando tenti di accedervi. Questo processo non è ideale in quanto il codice che riceve l'eccezione (il callback o il codice che utilizza `Future<?>`) non dispone del contesto della chiamata originale e può non essere in grado di gestire l'eccezione in modo adeguato. Inoltre, in un sistema asincrono distribuito in cui i componenti sono eseguiti simultaneamente, possono verificarsi più errori contemporaneamente. Questi errori possono essere di tipo e gravità differenti e devono essere gestiti in modo appropriato.

Anche la pulizia delle risorse dopo una chiamata asincrona risulta alquanto complessa. A differenza del codice sincrono, non è possibile utilizzarlo try/catch/finally nel codice chiamante per ripulire le risorse perché il lavoro iniziato nel blocco try potrebbe essere ancora in corso quando viene eseguito il blocco finally.

Il framework fornisce un meccanismo che rende la gestione degli errori nel codice asincrono distribuito simile e quasi altrettanto semplice di quella di Java. try/catch/finally

```
ImageProcessingActivitiesClient activitiesClient
     = new ImageProcessingActivitiesClientImpl();

public void createThumbnail(final String webPageUrl) {

  new TryCatchFinally() {

    @Override
    protected void doTry() throws Throwable {
      List<String> images = getImageUrls(webPageUrl);
      for (String image: images) {
        Promise<String> localImage
            = activitiesClient.downloadImage(image);
        Promise<String> thumbnailFile
            = activitiesClient.createThumbnail(localImage);
        activitiesClient.uploadImage(thumbnailFile);
      }
    }

    @Override
    protected void doCatch(Throwable e) throws Throwable {

      // Handle exception and rethrow failures
      LoggingActivitiesClient logClient = new LoggingActivitiesClientImpl();
      logClient.reportError(e);
      throw new RuntimeException("Failed to process images", e);
    }

    @Override
    protected void doFinally() throws Throwable {
      activitiesClient.cleanUp();
    }
  };
}
```

Il funzionamento della classe `TryCatchFinally` e delle relative varianti, ovvero `TryFinally` e `TryCatch`, è simile a quello dei blocchi Java `try`/`catch`/`finally`. Tale classe consente di associare i gestori di eccezioni a blocchi di codice di flusso di lavoro che possono essere eseguiti come task asincroni e remoti. Il metodo `doTry()` è equivalente, a livello di logica, al blocco `try`. Il framework esegue automaticamente il codice in `doTry()`. Un elenco di oggetti `Promise` può essere passato al costruttore di `TryCatchFinally`. Il metodo `doTry` sarà eseguito quanto tutti gli oggetti `Promise `passati al costruttore diventano pronti. Se un'eccezione viene generata dal codice richiamato in modo asincrono da `doTry()`, tutto il lavoro in sospeso in `doTry()` viene annullato e `doCatch()` viene chiamato per gestire l'eccezione. Ad esempio, nell'elenco qui sopra, se `downloadImage` genera un'eccezione, `createThumbnail` e `uploadImage` verranno annullati. Infine, `doFinally()` viene chiamato quando tutto il lavoro asincrono risulta terminato (completato, non riuscito o annullato). Questo metodo può essere utilizzato per la pulizia delle risorse. Puoi inoltre nidificare queste classi in base alle esigenze aziendali.

Quando un'eccezione è restituita in `doCatch()`, il framework fornisce uno stack di chiamate logiche che include chiamate asincrone e remote. Ciò può rivelarsi utile per il debug, soprattutto se hai dei metodi asincroni che chiamano altri metodi asincroni. Ad esempio, un'eccezione da downloadImage genererà un'eccezione come quella riportata di seguito:

```
RuntimeException: error downloading image
  at downloadImage(Main.java:35)
  at ---continuation---.(repeated:1)
  at errorHandlingAsync$1.doTry(Main.java:24)
  at ---continuation---.(repeated:1)
…
```

## TryCatchFinally Semantica
<a name="errorhandling.trycatchfinally"></a>

L'esecuzione di un programma AWS Flow Framework per Java può essere visualizzata come un albero di rami in esecuzione simultanea. Una chiamata a un metodo asincrono, a un'attività e a `TryCatchFinally` crea un nuovo ramo in tale struttura. Ad esempio, il flusso di lavoro di elaborazione di immagini può essere rappresentato dalla struttura ad albero illustrata di seguito.

![\[Struttura di esecuzione asincrona\]](http://docs.aws.amazon.com/it_it/amazonswf/latest/awsflowguide/images/trycatchfinally.png)


Un errore in un ramo dell'esecuzione comporterà la rimozione di quel ramo, proprio come un'eccezione provoca la rimozione dello stack di chiamate in un programma Java. La rimozione risale lungo il ramo di esecuzione fino a che l'errore viene gestito o viene raggiunta la radice della struttura ad albero, nel qual caso l'esecuzione di flusso di lavoro viene terminata.

Il framework segnala gli errori che si verificano durante l'elaborazione di task come eccezioni. Associa i gestori di eccezioni (metodi `doCatch()`) definiti in `TryCatchFinally` a tutti i task creati dal codice nel metodo `doTry()` corrispondente. Se un'attività fallisce, ad esempio a causa di un timeout o di un'eccezione non gestita, verrà sollevata l'eccezione appropriata e verrà invocata la corrispondente per gestirla. `doCatch()` A tal fine, il framework collabora con Amazon SWF per propagare gli errori remoti e li resuscita come eccezioni nel contesto del chiamante.

## Annullamento
<a name="test.cancellation.resources"></a>

Quando si verifica un'eccezione nel codice sincrono, il controllo passa direttamente al blocco `catch`, ignorando il codice rimanente nel blocco `try`. Per esempio: 

```
try {
    a();
    b();
    c();
}
catch (Exception e) {
    e.printStackTrace();
}
```

In questo codice, se `b()` genera un'eccezione, `c()` non viene mai richiamato. Facciamo un raffronto con un flusso di lavoro:

```
new TryCatch() {

    @Override
    protected void doTry() throws Throwable {
        activityA();
        activityB();
        activityC();
    }

    @Override
    protected void doCatch(Throwable e) throws Throwable {
        e.printStackTrace();
    }
};
```

In questo caso, le chiamate a `activityA`, `activityB` e `activityC` hanno esito positivo e comportano la creazione di tre task che vengono eseguiti in modo asincrono. Supponiamo che successivamente il task per `activityB` restituisca un errore. Questo errore viene registrato nella cronologia da Amazon SWF. Per gestirlo, il framework dapprima tenterà di annullare tutti gli altri task originati nell'ambito dello stesso `doTry()`; in questo caso, `activityA` e `activityC`. Quanto tutti i task risultano terminati (annullati, non riusciti o completati), il metodo `doCatch()` appropriato verrà richiamato per gestire l'errore.

A differenza dell'esempio sincrono, dove `c()` non è mai stato eseguito, `activityC` è stato richiamato e un task è stato pianificato per l'esecuzione. Di conseguenza, il framework effettuerà un tentativo per annullarlo, ma non è garantito che tale operazione riesca. L'annullamento non è certo in quanto l'attività può essere già stata completata, può ignorare la richiesta di annullamento o può non riuscire a causa di un errore. Il framework garantisce tuttavia che la chiamata del metodo `doCatch()` verrà effettuata solo dopo il completamento di tutti i task avviati dal metodo `doTry()` corrispondente. Garantisce inoltre la chiamata di `doFinally()` solo dopo il completamento di tutti i task avviati da `doTry()` e `doCatch()`. Se, ad esempio, le attività dell'esempio precedente dipendono l'una dall'altra, ad esempio `activityB` dipende da `activityA` e `activityC` da`activityB`, l'annullamento `activityC` sarà immediato perché non è programmato in Amazon SWF fino al `activityB` completamento:

```
new TryCatch() {

    @Override
    protected void doTry() throws Throwable {
        Promise<Void> a = activityA();
        Promise<Void> b = activityB(a);
        activityC(b);
    }

    @Override
    protected void doCatch(Throwable e) throws Throwable {
        e.printStackTrace();
    }
};
```

### Heartbeat dell'attività
<a name="errorhandling.activity.heartbeat"></a>

Il meccanismo di cancellazione cooperativa di AWS Flow Framework for Java consente di annullare senza problemi le attività in corso. Quando si avvia l'annullamento, i task bloccati o in attesa di essere assegnati a un lavoratore vengono annullati automaticamente. Se, tuttavia, un task è già assegnato a un lavoratore, il framework richiederà all'attività di annullarlo. L'implementazione di attività deve gestire in modo esplicito queste richieste di annullamento. Ciò viene eseguito mediante la segnalazione dell'heartbeat dell'attività.

La segnalazione dell'heartbeat consente all'implementazione di attività di comunicare l'avanzamento di un task di attività in corso, il che è utile per il monitoraggio, e all'attività di verificare l'esistenza di richieste di annullamento. Il metodo `recordActivityHeartbeat` genera un'eccezione `CancellationException` se un annullamento è stato richiesto. L'implementazione di attività può rilevare questa eccezione e agire sulla richiesta di annullamento oppure può ignorare la richiesta non tenendo conto dell'eccezione. Per soddisfare la richiesta di cancellazione, l'attività deve eseguire l'eventuale pulizia desiderata e quindi generare di nuovo `CancellationException`. Quando questa eccezione viene generata a partire da un'implementazione di attività, il framework registra che il task di attività è stato completato con lo stato annullato.

L'esempio seguente mostra un'attività che scarica ed elabora immagini. L'attività genera l'heartbeat dopo l'elaborazione di ogni immagine e se viene richiesto l'annullamento, esegue la pulizia e genera di nuovo l'eccezione per confermare l'annullamento.

```
@Override
public void processImages(List<String> urls) {
    int imageCounter = 0;
    for (String url: urls) {
        imageCounter++;
        Image image = download(url);
        process(image);
        try {
            ActivityExecutionContext context
                 = contextProvider.getActivityExecutionContext();
            context.recordActivityHeartbeat(Integer.toString(imageCounter));
        } catch(CancellationException ex) {
            cleanDownloadFolder();
            throw ex;
        }
    }
}
```

La segnalazione dell'heartbeat dell'attività non è necessaria, ma è consigliata se l'attività è a esecuzione prolungata o se esegue operazioni dispendiose che intendi annullare in condizioni di errore. Devi chiamare `heartbeatActivityTask` periodicamente a partire dall'implementazione di attività.

In caso di timeout dell'attività, verrà generata l'eccezione `ActivityTaskTimedOutException` e `getDetails` sull'oggetto eccezione restituirà i dati passati all'ultima chiamata a `heartbeatActivityTask` riuscita per il task di attività corrispondente. L'implementazione di flusso di lavoro può utilizzare queste informazioni per determinare l'avanzamento prima del timeout del task di attività.

**Nota**  
Non è consigliabile eseguire il battito cardiaco troppo frequentemente perché Amazon SWF può limitare le richieste di heartbeat. Consulta la [Amazon Simple Workflow Service Developer Guide](https://docs.aws.amazon.com/amazonswf/latest/developerguide/) per conoscere i limiti imposti da Amazon SWF.

### Annullamento esplicito di un task
<a name="errorhandling.canceltask"></a>

Oltre alle condizioni di errore, vi sono altri casi in cui puoi annullare esplicitamente un task. Ad esempio, è possibile che un'attività per l'elaborazione di pagamenti mediante una carta di credito debba essere annullata se l'utente annulla l'ordine. Il framework ti consente di annullare esplicitamente i task creati nell'ambito di una classe `TryCatchFinally`. Nell'esempio seguente, il task di pagamento viene annullato se si riceve un segnale durante l'elaborazione del pagamento.

```
public class OrderProcessorImpl implements OrderProcessor {
    private PaymentProcessorClientFactory factory
        = new PaymentProcessorClientFactoryImpl();
    boolean processingPayment = false;
    private TryCatchFinally paymentTask = null;

    @Override
    public void processOrder(int orderId, final float amount) {
        paymentTask = new TryCatchFinally() {

            @Override
            protected void doTry() throws Throwable {
                processingPayment = true;

                PaymentProcessorClient paymentClient = factory.getClient();
                paymentClient.processPayment(amount);
            }

            @Override
            protected void doCatch(Throwable e) throws Throwable {
                if (e instanceof CancellationException) {
                    paymentClient.log("Payment canceled.");
                } else {
                    throw e;
                }
            }

            @Override
            protected void doFinally() throws Throwable {
                processingPayment = false;
            }
        };

    }

    @Override
    public void cancelPayment() {
        if (processingPayment) {
            paymentTask.cancel(null);
        }
    }
}
```

### Ricezione di notifiche relative a task annullati
<a name="errorhandling.canceltask.notification"></a>

Se un task viene completato quando lo stato è annullato, il framework informa la logica di flusso di lavoro generando un'eccezione `CancellationException`. Se un'attività viene completata quando lo stato è annullata, un record viene creato nella cronologia e il framework chiama il metodo `doCatch()` appropriato con un'eccezione `CancellationException`. Come mostrato nell'esempio precedente, quando il task di elaborazione del pagamento viene annullato, il workflow riceve un'eccezione `CancellationException`. 

Un'eccezione `CancellationException` non gestita viene propagata nel ramo di esecuzione come avviene con qualsiasi altra eccezione. Tuttavia, il metodo `doCatch()` riceverà l'eccezione `CancellationException` solo se non vi sono altre eccezioni nell'ambito, in quanto la priorità delle altre eccezioni è superiore a quella dell'annullamento. 

## Annidato TryCatchFinally
<a name="errorhandling.nested"></a>

Puoi nidificare la classe `TryCatchFinally` in funzione delle tue esigenze. Poiché ognuno `TryCatchFinally` crea un nuovo ramo nell'albero di esecuzione, è possibile creare ambiti annidati. Le eccezioni nell'ambito padre comporteranno tentativi di annullamento di tutti i task avviati dalle classi `TryCatchFinally` nidificate nell'ambito. Tuttavia, le eccezioni in una classe `TryCatchFinally` nidificata non vengono propagate automaticamente al padre. Se desideri propagare un'eccezione da una classe `TryCatchFinally` nidificata alla classe `TryCatchFinally` che la contiene, devi generare di nuovo l'eccezione in `doCatch()`. In altre parole, solo le eccezioni non gestite sono propagate, esattamente come i blocchi Java `try`/`catch`. Se annulli una classe `TryCatchFinally` nidificata chiamando il metodo Cancel, la classe `TryCatchFinally` nidificata verrà annullata ma non la classe `TryCatchFinally` che la contiene.

![\[Annidato TryCatchFinally\]](http://docs.aws.amazon.com/it_it/amazonswf/latest/awsflowguide/images/nested.png)


```
new TryCatch() {
    @Override
    protected void doTry() throws Throwable {
        activityA();

        new TryCatch() {
            @Override
            protected void doTry() throws Throwable {
                activityB();
            }

            @Override
            protected void doCatch(Throwable e) throws Throwable {
                reportError(e);
            }
        };

        activityC();
    }

    @Override
    protected void doCatch(Throwable e) throws Throwable {
        reportError(e);
    }
};
```

# Ripetere le attività non andate a buon fine
<a name="features-retry"></a>

A volte le attività non vanno a buon fine per ragioni effimere, ad esempio una perdita temporanea della connessione. In altri casi l'attività va a buon fine, quindi il modo corretto di gestire l'errore è spesso quello di ripetere l'attività, anche più volte. 

Esiste una serie di strategie per ripetere le attività; la migliore dipende dai dettagli del flusso di lavoro. Tali strategie rientrano in tre categorie di base: 
+ La retry-until-success strategia continua semplicemente a riprovare l'attività fino al suo completamento.
+ La strategia di ripetizione esponenziale aumenta esponenzialmente l'intervallo di tempo tra i tentativi fino al completamento dell'attività o fino a quando il processo raggiunge un punto di arresto specifico, come un numero massimo di tentativi.
+ La strategia di ripetizione personalizzata decide se o come ripetere l'attività dopo ciascun tentativo non andato a buon fine.

Le sezioni seguenti descrivono come implementare queste strategie. I lavoratori del flusso di lavoro di esempio utilizzano tutti una singola attività, `unreliableActivity`, che esegue casualmente una delle seguenti operazioni: 
+ Viene completata immediatamente
+ Non va a buon fine intenzionalmente superando il valore di timeout
+ Non va a buon fine intenzionalmente generando `IllegalStateException` 

## Retry-Until-Success Strategia
<a name="features-retry-success"></a>

La strategia più semplice è quella di ripetere l'attività ogni volta che ha esito negativo fino al buon esito. Il modello di base è:

1. Implementare una classe nidificata `TryCatch` o `TryCatchFinally` nel metodo del punto di ingresso del flusso di lavoro.

1. Eseguire l'attività in `doTry`.

1. Se l'attività non va a buon fine, il framework chiama `doCatch`, che esegue nuovamente il metodo del punto di ingresso.

1. Ripetere le fasi 2 e 3 fino al completamento con esito positivo dell'attività.

Il seguente flusso di lavoro implementa la retry-until-success strategia. L'interfaccia del flusso di lavoro è implementata in `RetryActivityRecipeWorkflow` e ha un metodo, `runUnreliableActivityTillSuccess`, che è il punto di ingresso del flusso di lavoro. Il lavoratore del flusso di lavoro viene implementato in `RetryActivityRecipeWorkflowImpl`, nel seguente modo: 

```
public class RetryActivityRecipeWorkflowImpl
    implements RetryActivityRecipeWorkflow {

    @Override
    public void runUnreliableActivityTillSuccess() {
        final Settable<Boolean> retryActivity = new Settable<Boolean>();

        new TryCatch() {
            @Override
            protected void doTry() throws Throwable {
                Promise<Void> activityRanSuccessfully
                    = client.unreliableActivity();
                setRetryActivityToFalse(activityRanSuccessfully, retryActivity);
            }

            @Override
            protected void doCatch(Throwable e) throws Throwable {
                retryActivity.set(true);
            }
        };
        restartRunUnreliableActivityTillSuccess(retryActivity);
    }

    @Asynchronous
    private void setRetryActivityToFalse(
            Promise<Void> activityRanSuccessfully,
            @NoWait Settable<Boolean> retryActivity) {
        retryActivity.set(false);
    }

    @Asynchronous
    private void restartRunUnreliableActivityTillSuccess(
            Settable<Boolean> retryActivity) {
        if (retryActivity.get()) {
            runUnreliableActivityTillSuccess();
        }
    }
}
```

Il flusso di lavoro funziona come segue: 

1. `runUnreliableActivityTillSuccess` crea un oggetto `Settable<Boolean>` denominato `retryActivity` che viene usato per indicare se l'attività non è riuscita e deve essere ritentata. `Settable<T>` è derivato da `Promise<T>` e funziona allo stesso modo ma il valore dell'oggetto `Settable<T>` viene impostato manualmente.

1. `runUnreliableActivityTillSuccess` implementa una classe annidata anonima `TryCatch` per gestire le eccezioni generate dall'attività `unreliableActivity`. Per ulteriori discussioni su come gestire le eccezioni generate da un codice asincrono, consulta [Gestione errori](errorhandling.md).

1. `doTry` esegue l'attività `unreliableActivity`, che restituisce un oggetto `Promise<Void>` di nome `activityRanSuccessfully`.

1. `doTry` chiama il metodo asincrono `setRetryActivityToFalse`, che ha due parametri:
   + `activityRanSuccessfully` accetta l'oggetto `Promise<Void>` restituito dall'attività `unreliableActivity`.
   + `retryActivity` accetta l'oggetto `retryActivity`.

   Se `unreliableActivity` viene completato, `activityRanSuccessfully` diventa pronto e `setRetryActivityToFalse` imposta `retryActivity` su false. In caso contrario, `activityRanSuccessfully` non diventa mai pronto e `setRetryActivityToFalse` non viene eseguito.

1. Se `unreliableActivity` genera un'eccezione, il framework chiama `doCatch` e lo trasferisce all'oggetto dell'eccezione. `doCatch` imposta `retryActivity` su true.

1. `runUnreliableActivityTillSuccess` chiama il metodo asincrono `restartRunUnreliableActivityTillSuccess` e lo trasferisce all'oggetto `retryActivity`. Poiché `retryActivity` è un tipo `Promise<T>`, `restartRunUnreliableActivityTillSuccess` ritarda l'esecuzione fin quando `retryActivity` è pronto, il che si verifica dopo il completamento di `TryCatch`. 

1. Quando `retryActivity` è pronto, `restartRunUnreliableActivityTillSuccess` estrae il valore.
   + Se il valore è `false`, il nuovo tentativo è andato a buon fine. `restartRunUnreliableActivityTillSuccess` non è operativo e la sequenza di ripetizione termina.
   + Se il valore è true, il nuovo tentativo non è andato a buon fine. `restartRunUnreliableActivityTillSuccess` chiama `runUnreliableActivityTillSuccess` per eseguire nuovamente l'attività.

1. Si ripetono le fasi 1-7 fino al completamento di `unreliableActivity`. 

**Nota**  
`doCatch` non gestisce l'eccezione; imposta semplicemente l'oggetto `retryActivity` su true per indicare l'esito negativo dell'attività. La ripetizione è gestita dal metodo asincrono `restartRunUnreliableActivityTillSuccess`, che ritarda l'esecuzione fino al completamento di `TryCatch`. Il motivo di questo approccio è che se riprovi un'attività in `doCatch` non puoi annullarla. Ripetere l'attività in `restartRunUnreliableActivityTillSuccess` ti permette di eseguire attività annullabili. 

## Strategia di ripetizione esponenziale
<a name="features-retry-exponential"></a>

Con la strategia di ripetizione esponenziale, il framework esegue nuovamente un'attività non andata a buon fine dopo un periodo di tempo specifico, N secondi. Se il tentativo ha esito negativo, il framework esegue nuovamente l'attività dopo 2N secondi, 4N secondi e così via. Poiché il tempo di attesa può essere lungo, in genere i tentativi si arrestano a un certo punto invece che proseguire all'infinito.

Il framework prevede tre modi per implementare una strategia di ripetizione esponenziale:
+ L'annotazione `@ExponentialRetry` è l'approccio più semplice, ma devi impostare le opzioni di configurazione della ripetizione al momento della compilazione.
+ La classe `RetryDecorator` ti permette di impostare la configurazione della ripetizione in fase di runtime e di modificarla in base alle necessità.
+ La classe `AsyncRetryingExecutor` ti permette di impostare la configurazione della ripetizione in fase di runtime e di modificarla in base alle necessità. Inoltre, il framework chiama un metodo `AsyncRunnable.run` implementato dall'utente per eseguire ogni tentativo di ripetizione.

Tutti gli approcci supportano le seguenti opzioni di configurazione, in cui i valori di tempo sono espressi in secondi: 
+ Il tempo di attesa per la ripetizione iniziale.
+ Il coefficiente di backoff, che viene utilizzato per calcolare gli intervalli di ripetizione, nel modo seguente:

  ```
  retryInterval = initialRetryIntervalSeconds * Math.pow(backoffCoefficient, numberOfTries - 2)
  ```

  Il valore predefinito è 2.0.
+ Il numero massimo di tentativi di ripetizione. Il valore predefinito è illimitato.
+ L'intervallo massimo di ripetizione. Il valore predefinito è illimitato.
+ Il tempo di scadenza. I tentativi si arrestano quando la durata totale del processo supera questo valore. Il valore predefinito è illimitato.
+ Le eccezioni che attivano il processo di ripetizione. Per impostazione predefinita, tutte le eccezioni attivano il processo di ripetizione.
+ Le eccezioni che non attivano tentativi di ripetizione. Per impostazione predefinita, non è esclusa alcuna eccezione.

Le sezioni seguenti descrivono i vari modi in cui è possibile implementare una strategia di ripetizione esponenziale.

### Riprova esponenziale con @ ExponentialRetry
<a name="features-retry-exponential-annotation"></a>

Il modo più semplice per implementare una strategia di ripetizione esponenziale per un'attività è applicare un'annotazione `@ExponentialRetry ` all'attività nella definizione dell'interfaccia. Se l'attività non va a buon fine, il framework gestisce automaticamente il processo di ripetizione in base ai valori opzionali specificati. Il modello di base è:

1. Applica `@ExponentialRetry` alle attività in questione e specifica la configurazione di ripetizione.

1. Se l'attività annotata non va a buon fine, il framework la recupera automaticamente secondo la configurazione specificata dagli argomenti dell'annotazione. 

Il lavoratore del flusso di lavoro `ExponentialRetryAnnotationWorkflow` implementa la strategia di ripetizione esponenziale utilizzando un'annotazione `@ExponentialRetry`. Utilizza un'attività `unreliableActivity` la cui definizione dell'interfaccia è implementata in `ExponentialRetryAnnotationActivities`, nel modo seguente:

```
@Activities(version = "1.0")
@ActivityRegistrationOptions(
    defaultTaskScheduleToStartTimeoutSeconds = 30,
    defaultTaskStartToCloseTimeoutSeconds = 30)
public interface ExponentialRetryAnnotationActivities {
    @ExponentialRetry(
        initialRetryIntervalSeconds = 5,
        maximumAttempts = 5,
        exceptionsToRetry = IllegalStateException.class)
    public void unreliableActivity();
}
```

Le opzioni di `@ExponentialRetry` specificano la seguente strategia: 
+ Ripeti sono se l'attività genera `IllegalStateException`.
+ Utilizza un tempo di attesa iniziale di 5 secondi.
+ Non più di 5 tentativi di ripetizione. 

L'interfaccia del flusso di lavoro è implementata in `RetryWorkflow` e ha un metodo, `process`, che è il punto di ingresso del flusso di lavoro. Il lavoratore del flusso di lavoro viene implementato in `ExponentialRetryAnnotationWorkflowImpl`, nel seguente modo: 

```
public class ExponentialRetryAnnotationWorkflowImpl implements RetryWorkflow {
    public void process() {
        handleUnreliableActivity();
    }

    public void handleUnreliableActivity() {
        client.unreliableActivity();
    }
}
```

Il flusso di lavoro funziona come segue: 

1. `process` esegue il metodo asincrono `handleUnreliableActivity`.

1. `handleUnreliableActivity` esegue l'attività `unreliableActivity`. 

Se l'attività non va a buon fine generando `IllegalStateException`, il framework esegue automaticamente la strategia di ripetizione specificata in `ExponentialRetryAnnotationActivities`.

### Riprova esponenziale con la classe RetryDecorator
<a name="features-retry-exponential-decorator"></a>

`@ExponentialRetry` è semplice da usare. Tuttavia, la configurazione è statica e impostata al momento della compilazione, in modo che il framework utilizzi la stessa strategia di ripetizione ogni volta che l'attività non va a buon fine. Puoi implementare una strategia di ripetizione esponenziale più flessibile utilizzando la classe `RetryDecorator`, che ti permette di specificare la configurazione in fase di runtime e di modificarla in base alle necessità. Il modello di base è:

1. Crea e configura un oggetto `ExponentialRetryPolicy` che specifichi la configurazione della ripetizione.

1. Crea un oggetto `RetryDecorator` e trasferisci l'oggetto `ExponentialRetryPolicy` della Fase 1 al costruttore.

1. Applica l'oggetto decorator all'attività trasferendo il nome della classe del client di attività al metodo decorato dell'oggetto `RetryDecorator`.

1. Esegui l'attività.

Se l'attività non va a buon fine, il framework la ripete secondo la configurazione dell'oggetto `ExponentialRetryPolicy`. Puoi modificare la configurazione della ripetizione in base alla necessità cambiando l'oggetto. 

**Nota**  
L'annotazione `@ExponentialRetry` e la classe `RetryDecorator` sono reciprocamente esclusive. Non puoi utilizzare `RetryDecorator` per sovrascrivere dinamicamente una policy di ripetizione specificata da un'annotazione `@ExponentialRetry`. 

La seguente implementazione del flusso di lavoro mostra come utilizzare la classe `RetryDecorator` per implementare una strategia di ripetizione esponenziale. Utilizza un'attività `unreliableActivity` priva dell'annotazione `@ExponentialRetry`. L'interfaccia del flusso di lavoro è implementata in `RetryWorkflow` e ha un metodo, `process`, che è il punto di ingresso del flusso di lavoro. Il lavoratore del flusso di lavoro viene implementato in `DecoratorRetryWorkflowImpl`, nel seguente modo: 

```
public class DecoratorRetryWorkflowImpl implements RetryWorkflow {
   ...
  public void process() {
      long initialRetryIntervalSeconds = 5;
      int maximumAttempts = 5;
      ExponentialRetryPolicy retryPolicy = new ExponentialRetryPolicy(
              initialRetryIntervalSeconds).withMaximumAttempts(maximumAttempts);

      Decorator retryDecorator = new RetryDecorator(retryPolicy);
      client = retryDecorator.decorate(RetryActivitiesClient.class, client);
      handleUnreliableActivity();
  }

  public void handleUnreliableActivity() {
      client.unreliableActivity();
  }
}
```

Il flusso di lavoro funziona come segue: 

1. `process` crea e configura un oggetto `ExponentialRetryPolicy` nel seguente modo: 
   + Trasferendo al costruttore l'intervallo di ripetizione iniziale.
   + Chiamando il metodo `withMaximumAttempts` dell'oggetto per impostare il numero massimo di tentativi a 5. `ExponentialRetryPolicy` espone altri oggetti `with` che è possibile usare per specificare altre opzioni di configurazione.

1. `process` crea un oggetto `RetryDecorator` con nome `retryDecorator` e trasferisce l'oggetto `ExponentialRetryPolicy` della Fase 1 al costruttore.

1. `process` applica l'elemento decorator all'attività chiamando il metodo `retryDecorator.decorate` e trasferendolo al nome della classe del client di attività.

1. `handleUnreliableActivity` esegue l'attività. 

Se l'attività non va a buon fine, il framework la ripete secondo la configurazione specificata nella Fase 1.

**Nota**  
Molti dei metodi `with` della classe `ExponentialRetryPolicy` hanno un metodo corrispondente `set` che puoi chiamare per modificare l'opzione di configurazione corrispondente in qualsiasi momento: `setBackoffCoefficient`, `setMaximumAttempts`, `setMaximumRetryIntervalSeconds` e `setMaximumRetryExpirationIntervalSeconds`. 

### Riprova esponenziale con la classe AsyncRetryingExecutor
<a name="features-retry-exponential-async"></a>

La classe `RetryDecorator` offre più flessibilità nella configurazione del processo di ripetizione rispetto a `@ExponentialRetry`, ma il framework esegue comunque automaticamente i tentativi di ripetizione, in base alla attuale configurazione dell'oggetto `ExponentialRetryPolicy`. Un approccio più flessibile prevede l'utilizzo della classe `AsyncRetryingExecutor`. Oltre a permetterti di configurare il processo di ripetizione in fase di runtime, il framework chiama un metodo `AsyncRunnable.run` implementato dall'utente per eseguire ogni tentativo di ripetizione invece che eseguire semplicemente l'attività.

Il modello di base è: 

1. Crea e configura un oggetto `ExponentialRetryPolicy` per specificare la configurazione della ripetizione.

1. Crea un oggetto `AsyncRetryingExecutor` e trasferiscigli l'oggetto `ExponentialRetryPolicy` e un'istanza dell'orologio del flusso di lavoro.

1.  Implementa una classe annidata anonima `TryCatch` o `TryCatchFinally`.

1. Implementa una classe anonima `AsyncRunnable` e sovrascrivi il metodo `run` per implementare il codice personalizzato per eseguire l'attività.

1.  Sovrascrivi `doTry` per chiamare il metodo `execute` dell'oggetto `AsyncRetryingExecutor` e trasferirlo alla classe `AsyncRunnable` dalla fase 4. L'oggetto `AsyncRetryingExecutor` chiama `AsyncRunnable.run` per eseguire l'attività.

1. Se l'attività non va a buon fine, l'oggetto `AsyncRetryingExecutor` chiama nuovamente il metodo `AsyncRunnable.run` secondo la policy di ripetizione specificata nella Fase 1. 

Il flusso di lavoro seguente mostra come utilizzare la classe `AsyncRetryingExecutor` per implementare una strategia di ripetizione esponenziale. Utilizza la stessa attività `unreliableActivity` del flusso di lavoro `DecoratorRetryWorkflow` discusso in precedenza. L'interfaccia del flusso di lavoro è implementata in `RetryWorkflow` e ha un metodo, `process`, che è il punto di ingresso del flusso di lavoro. Il lavoratore del flusso di lavoro viene implementato in `AsyncExecutorRetryWorkflowImpl`, nel seguente modo: 

```
public class AsyncExecutorRetryWorkflowImpl implements RetryWorkflow {
  private final RetryActivitiesClient client = new RetryActivitiesClientImpl();
  private final DecisionContextProvider contextProvider = new DecisionContextProviderImpl();
  private final WorkflowClock clock = contextProvider.getDecisionContext().getWorkflowClock();

  public void process() {
      long initialRetryIntervalSeconds = 5;
      int maximumAttempts = 5;
      handleUnreliableActivity(initialRetryIntervalSeconds, maximumAttempts);
  }
  public void handleUnreliableActivity(long initialRetryIntervalSeconds, int maximumAttempts) {

      ExponentialRetryPolicy retryPolicy = new ExponentialRetryPolicy(initialRetryIntervalSeconds).withMaximumAttempts(maximumAttempts);
      final AsyncExecutor executor = new AsyncRetryingExecutor(retryPolicy, clock);

      new TryCatch() {
          @Override
          protected void doTry() throws Throwable {
              executor.execute(new AsyncRunnable() {
                  @Override
                  public void run() throws Throwable {
                      client.unreliableActivity();
                  }
              });
          }
          @Override
          protected void doCatch(Throwable e) throws Throwable {
          }
      };
  }
}
```

Il flusso di lavoro funziona come segue: 

1. `process` chiama il metodo `handleUnreliableActivity` e lo trasferisce alle impostazioni della configurazione.

1. `handleUnreliableActivity` utilizza le impostazioni di configurazione della Fase 1 per creare un oggetto `ExponentialRetryPolicy`, l'oggetto `retryPolicy`.

1. `handleUnreliableActivity` crea un oggetto `AsyncRetryExecutor`, `executor` e trasferisce l'oggetto `ExponentialRetryPolicy` della Fase 2 e un'istanza dell'orologio del flusso di lavoro al costruttore

1.  `handleUnreliableActivity` implementa una classe annidata anonima `TryCatch` e sovrascrive i metodi `doTry` e `doCatch` per eseguire i tentativi di ripetizione e gestire le eventuali eccezioni.

1. `doTry` crea una classe anonima `AsyncRunnable` e sovrascrive il metodo `run` per implementare il codice personalizzato per eseguire `unreliableActivity`. Per semplicità, `run` esegue semplicemente l'attività, ma puoi implementare approcci più sofisticati in base alle necessità.

1. `doTry` chiama `executor.execute` e lo trasferisce all'oggetto `AsyncRunnable`. `execute` chiama il metodo `AsyncRunnable` dell'oggetto `run` per eseguire l'attività.

1. Se l'attività non va a buon fine, l'esecutore chiama di nuovo `run` in base alla configurazione dell'oggetto `retryPolicy`. 

Per ulteriori discussioni su come utilizzare la classe `TryCatch` per gestire gli errori, consulta [AWS Flow Framework per le eccezioni Java](errorhandling.exceptions.md). 

## Strategia di ripetizione personalizzata
<a name="custom-retry-strategy"></a>

L'approccio più flessibile per riprovare le attività non riuscite è una strategia personalizzata, che richiama ricorsivamente un metodo asincrono che esegue il tentativo di nuovo tentativo, proprio come la strategia. retry-until-success Tuttavia, invece che rieseguire semplicemente l'attività, implementi una logica personalizzata che decide se e come eseguire i successivi tentativi di ripetizione. Il modello di base è: 

1. Crea un oggetto di stato `Settable<T>`, che viene utilizzato per indicare se l'attività non è andata a buon fine.

1. Implementa una classe annidata `TryCatch` o `TryCatchFinally`.

1. `doTry` esegue l'attività.

1. Se l'attività non va a buon fine, `doCatch` imposta l'oggetto di stato per indicare che l'attività ha avuto esito negativo.

1. Chiama un metodo asincrono di gestione dell'errore e trasferiscilo all'oggetto di stato. Il metodo ritarda l'esecuzione fino al completamento di `TryCatch` o `TryCatchFinally`.

1. Il metodo di gestione dell'errore decide se e quando ripetere l'attività.

Il flusso di lavoro seguente mostra come implementare una strategia di ripetizione personalizzata. Utilizza la stessa attività `unreliableActivity` dei flussi di lavoro `DecoratorRetryWorkflow` e `AsyncExecutorRetryWorkflow`. L'interfaccia del flusso di lavoro è implementata in `RetryWorkflow` e ha un metodo, `process`, che è il punto di ingresso del flusso di lavoro. Il lavoratore del flusso di lavoro viene implementato in `CustomLogicRetryWorkflowImpl`, nel seguente modo: 

```
public class CustomLogicRetryWorkflowImpl implements RetryWorkflow {
  ...
  public void process() {
      callActivityWithRetry();
  }
  @Asynchronous
  public void callActivityWithRetry() {
      final Settable<Throwable> failure = new Settable<Throwable>();
      new TryCatchFinally() {
          protected void doTry() throws Throwable {
              client.unreliableActivity();
          }
          protected void doCatch(Throwable e) {
              failure.set(e);
          }
          protected void doFinally() throws Throwable {
              if (!failure.isReady()) {
                  failure.set(null);
              }
          }
      };
      retryOnFailure(failure);
  }
  @Asynchronous
  private void retryOnFailure(Promise<Throwable> failureP) {
      Throwable failure = failureP.get();
      if (failure != null && shouldRetry(failure)) {
          callActivityWithRetry();
      }
  }
  protected Boolean shouldRetry(Throwable e) {
      //custom logic to decide to retry the activity or not
      return true;
  }
}
```

Il flusso di lavoro funziona come segue:

1. `process` chiama il metodo asincrono `callActivityWithRetry`.

1. `callActivityWithRetry` crea un errore di oggetto `Settable<Throwable>` denominato che viene utilizzato per indicare se l'attività non è andata a buon fine. `Settable<T>` deriva da `Promise<T>` e funziona quasi allo stesso modo, ma il valore dell'oggetto `Settable<T>` è impostato manualmente.

1. `callActivityWithRetry` implementa una classe annidata anonima `TryCatchFinally` per gestire le eccezioni generate da `unreliableActivity`. Per ulteriori discussioni su come gestire le eccezioni generate da un codice asincrono, consulta [AWS Flow Framework per le eccezioni Java](errorhandling.exceptions.md).

1. `doTry` esegue `unreliableActivity`.

1. Se `unreliableActivity` genera un'eccezione, il framework chiama `doCatch` e lo trasferisce all'oggetto dell'eccezione. `doCatch` imposta `failure` sull'oggetto dell'eccezione, il che indica che l'attività non è andata a buon fine e mette l'oggetto in stato di pronto.

1. `doFinally` verifica se `failure` è pronto, che sarà vero solo se `failure` è stato impostato da `doCatch`.
   + Se è pronto, non fa nulla. `failure` `doFinally`
   + Se `failure` non è pronto, l'attività viene completata e `doFinally` imposta l'errore su `null`. 

1. `callActivityWithRetry` chiama il metodo asincrono `retryOnFailure` e vi trasferisce l'errore. Poiché l'errore è un tipo `Settable<T>`, `callActivityWithRetry` ritarda l'esecuzione fin quando l'errore è pronto, il che si verifica dopo il completamento di `TryCatchFinally`.

1. `retryOnFailure` riceve il valore dall'errore.
   + Se l'errore è impostato su null, il tentativo di ripetizione è andato a buon fine. `retryOnFailure` non fa alcunché, il che termina il processo di ripetizione.
   + Se l'errore è impostato su un oggetto di eccezione e `shouldRetry` restituisce il valore true, `retryOnFailure` chiama `callActivityWithRetry` per riprovare l'attività. 

     `shouldRetry` implementa una logica personalizzata per decidere se ripetere un'attività dall'esito negativo. Per semplicità, `shouldRetry` restituisce sempre il valore `true` e `retryOnFailure` esegue immediatamente l'attività, ma puoi implementare una logica più sofisticata in base alle necessità. 

1. I passaggi da 2 a 8 si ripetono fino al `unreliableActivity` completamento o alla `shouldRetry` decisione di interrompere il processo. 

**Nota**  
`doCatch` non gestisce il processo di ripetizione; imposta semplicemente l'errore per indicare l'esito negativo dell'attività. Il processo di ripetizione è gestito dal metodo asincrono `retryOnFailure`, che ritarda l'esecuzione fino al completamento di `TryCatch`. Il motivo di questo approccio è che se riprovi un'attività in `doCatch` non puoi annullarla. Ripetere l'attività in `retryOnFailure` ti permette di eseguire attività annullabili. 

# Task Daemon
<a name="daemontasks"></a>

Il AWS Flow Framework for Java consente di contrassegnare determinate attività come`daemon`. Questa funzionalità ti permette di creare task che effettuano un lavoro di background che deve essere annullato quando tutti gli altri lavori sono stati eseguiti. Ad esempio, un task di monitoraggio dello stato deve essere annullato quando il resto del flusso di lavoro è completato. Puoi farlo impostando il contrassegno `daemon` su un metodo asincrono o un'istanza di `TryCatchFinally`. Nell'esempio seguente, il metodo asincrono `monitorHealth()` è contrassegnato come `daemon`.

```
public class MyWorkflowImpl implements MyWorkflow {
  MyActivitiesClient activitiesClient = new MyActivitiesClientImpl();

  @Override
  public void startMyWF(int a, String b) {
    activitiesClient.doUsefulWorkActivity();
    monitorHealth();
  }

  @Asynchronous(daemon=true)
  void monitorHealth(Promise<?>... waitFor) {
    activitiesClient.monitoringActivity();
  }
}
```

Nell'esempio riportato sopra, quando `doUsefulWorkActivity` viene completato, `monitoringHealth` viene automaticamente annullato. Questa operazione annulla l'intero ramo di esecuzione radicato nel metodo asincrono. La semantica dell'annullamento è identica a quella di `TryCatchFinally`. Analogamente, puoi contrassegnare un daemon `TryCatchFinally` passando un contrassegno Boolean al costruttore.

```
public class MyWorkflowImpl implements MyWorkflow {
    MyActivitiesClient activitiesClient = new MyActivitiesClientImpl();

    @Override
    public void startMyWF(int a, String b) {
        activitiesClient.doUsefulWorkActivity();
        new TryFinally(true) {
            @Override
            protected void doTry() throws Throwable {
                activitiesClient.monitoringActivity();
            }

            @Override
            protected void doFinally() throws Throwable {
                // clean up
            }
        };
    }
}
```

Un'operazione daemon avviata all'interno di a `TryCatchFinally` è limitata al contesto in cui è stata creata, ovvero sarà limitata ai metodi, o. `doTry()` `doCatch()` `doFinally()` Nel seguente esempio il metodo asincrono startMonitoring viene contrassegnato come daemon e chiamato da `doTry()`. Il task creato verrà annullato non appena gli altri task (`doUsefulWorkActivity` in questo caso) avviati entro `doTry()` saranno completati.

```
public class MyWorkflowImpl implements MyWorkflow {
    MyActivitiesClient activitiesClient = new MyActivitiesClientImpl();

    @Override
    public void startMyWF(int a, String b) {
        new TryFinally() {
            @Override
            protected void doTry() throws Throwable {
                activitiesClient.doUsefulWorkActivity();
                startMonitoring();
            }

            @Override
            protected void doFinally() throws Throwable {
                // Clean up
            }
        };
    }

    @Asynchronous(daemon = true)
    void startMonitoring(){
      activitiesClient.monitoringActivity();
    }
```

# AWS Flow Framework per Java Replay Behavior
<a name="programming-replay"></a>

Questo argomento presenta alcuni esempi relativi al comportamento di riproduzione, in base a quanto descritto nella sezione [Che cos'è AWS Flow Framework per Java?](welcome.md). Gli esempi forniti riguardano la riproduzione [sincrona](#programming-replay-synchronous) e a quella [asincrona](#programming-replay-asynchronous).

## Esempio 1: riproduzione sincrona
<a name="programming-replay-synchronous"></a>

Per un esempio di come funziona la replay in un flusso di lavoro sincrono, modificate le implementazioni del flusso di [HelloWorldWorkflow](getting-started-example-helloworldworkflow.md)lavoro e delle attività aggiungendo `println` chiamate all'interno delle rispettive implementazioni, come segue:

```
public class GreeterWorkflowImpl implements GreeterWorkflow {
...
   public void greet() {
      System.out.println("greet executes");
      Promise<String> name = operations.getName();
      System.out.println("client.getName returns");
      Promise<String> greeting = operations.getGreeting(name);
      System.out.println("client.greeting returns");
      operations.say(greeting);
      System.out.println("client.say returns");
   }
}
**************
public class GreeterActivitiesImpl implements GreeterActivities {
   public String getName() {
      System.out.println("activity.getName completes");
      return "World";
   }

   public String getGreeting(String name) {
      System.out.println("activity.getGreeting completes");
      return "Hello " + name + "!";
   }

   public void say(String what) {
      System.out.println(what);
   }
}
```

Per dettagli sul codice, consulta [HelloWorldWorkflow Applicazione](getting-started-example-helloworldworkflow.md). Quanto segue è una versione modificata dell'output, con commenti che indicano l'avvio di ogni episodio di riproduzione.

```
//Episode 1
greet executes
client.getName returns
client.greeting returns
client.say returns

activity.getName completes
//Episode 2
greet executes
client.getName returns
client.greeting returns
client.say returns

activity.getGreeting completes
//Episode 3
greet executes
client.getName returns
client.greeting returns
client.say returns

Hello World! //say completes
//Episode 4
greet executes
client.getName returns
client.greeting returns
client.say returns
```

Il processo di riproduzione in questo esempio è il seguente:
+ Il primo episodio pianifica il task di attività `getName`, che non ha dipendenze.
+ Il secondo episodio pianifica il task di attività `getGreeting`, che dipende da `getName`.
+ Il terzo episodio pianifica il task di attività `say`, che dipende da `getGreeting`.
+ L'episodio finale non pianifica altri task e non trova alcuna attività non completata, di conseguenza l'esecuzione di flusso di lavoro risulta completata. 

**Nota**  
I tre metodi di client di attività vengono chiamati una volta per ogni episodio. Tuttavia, solo una di queste chiamate genera un task di attività, quindi ogni task viene eseguito una sola volta.

## Esempio 2: riproduzione asincrona
<a name="programming-replay-asynchronous"></a>

Come per l'[esempio di riproduzione sincrona](#programming-replay-synchronous), puoi modificare [HelloWorldWorkflowAsync Applicazione](getting-started-example-helloworldworkflowasync.md) per osservare il funzionamento della riproduzione asincrona. Viene generato il seguente output:

```
//Episode 1
greet executes
client.name returns
workflow.getGreeting returns
client.say returns

activity.getName completes
//Episode 2
greet executes
client.name returns
workflow.getGreeting returns
client.say returns
workflow.getGreeting completes

Hello World! //say completes
//Episode 3
greet executes
client.name returns
workflow.getGreeting returns
client.say returns
workflow.getGreeting completes
```

HelloWorldAsync utilizza tre episodi di replay perché ci sono solo due attività. L'attività `getGreeting` è stata sostituita dal metodo di flusso di lavoro asincrono *getGreeting*, che, quando completato, non avvia un episodio di riproduzione.

Il primo episodio non chiama `getGreeting` poiché dipende dal completamento dell'attività *name*. Tuttavia, dopo il completamento di *getName*, la riproduzione chiama *getGreeting* una volta per ogni episodio successivo.

## Vedi anche
<a name="see-also"></a>
+ [AWS Flow Framework Concetti di base: esecuzione distribuita](awsflow-basics-distributed-execution.md)