Creare relazioni tra attività per eseguire attività che dipendono da altre attività

Con le dipendenze dell'attività Batch, si creano attività pianificate per l'esecuzione nei nodi di calcolo dopo il completamento di una o più attività padre. Ad esempio, è possibile creare un processo che esegue il rendering di ogni fotogramma di un film 3D con le attività parallele separate. L'attività finale unisce i fotogrammi di rendering nel film completo solo dopo il rendering di tutti i fotogrammi. In altre parole, l'attività finale dipende dalle attività padre precedenti.

Ecco alcuni degli scenari in cui le dipendenze delle attività sono utili:

  • Carichi di lavoro di tipo MapReduce nel cloud.
  • Processi le cui attività di elaborazione dati può essere espressa come grafo aciclico diretto (DAG).
  • Processi di pre-rendering e post-rendering, in cui ogni attività deve essere completata prima di poter avviare quella successiva.
  • Qualsiasi altro processo in cui le attività downstream dipendono l'output delle attività upstream.

Per impostazione predefinita, l'esecuzione delle attività dipendenti è pianificata solo dopo il corretto completamento dell'attività padre. Facoltativamente, è possibile specificare un'azione di dipendenza per eseguire l'override del comportamento predefinito ed eseguire l'attività dipendente anche se l'attività padre ha esito negativo.

Questo articolo illustra la configurazione di relazioni tra attività tramite la libreria Batch .NET. Viene illustrato prima come abilitare le dipendenze tra attività nei processi, quindi viene spiegato come configurare un'attività con dipendenze. Viene inoltre descritto come specificare un'azione di dipendenza per l'esecuzione di attività dipendenti se l'attività padre non riesce. Vengono infine illustrati gli scenari delle relazione supportate da Batch.

Abilitare le relazioni tra attività

Per usare le dipendenze delle attività nell'applicazione Batch, è innanzitutto necessario configurare il processo per l'uso delle dipendenze. In Batch .NET abilitare la funzionalità in CloudJob impostando la rispettiva proprietà UsesTaskDependencies su true:

CloudJob unboundJob = batchClient.JobOperations.CreateJob( "job001",
    new PoolInformation { PoolId = "pool001" });

// IMPORTANT: This is REQUIRED for using task dependencies.
unboundJob.UsesTaskDependencies = true;

Nel frammento di codice precedente "batchClient" è un'istanza della classe BatchClient.

Creare attività dipendenti

Per creare un'attività che dipende dal completamento di una o più attività padre, è possibile specificare che l'attività "dipende" dalle altre attività. In Batch .NET configurare la proprietà CloudTask.DependsOn con un'istanza della classe TaskDependencies :

// Task 'Flowers' depends on completion of both 'Rain' and 'Sun'
// before it is run.
new CloudTask("Flowers", "cmd.exe /c echo Flowers")
{
    DependsOn = TaskDependencies.OnIds("Rain", "Sun")
},

Questo frammento di codice crea un'attività dipendente con ID attività "Flowers". L'attività "Flowers" dipende dalle attività "Rain" e "Sun". L'esecuzione dell'attività "Flowers" in un nodo di calcolo verrà pianificata solo dopo il corretto completamento delle attività "Rain" e "Sun".

Nota

Per impostazione predefinita, un'attività viene considerata correttamente completata quando l'attività è in stato completato e il codice di uscita è 0. In Batch .NET questo significa che il valore della proprietà CloudTask.State è Completed e il valore della proprietà TaskExecutionInformation.ExitCode di CloudTask è 0. Per informazioni su come modificare questa operazione, vedere la sezione Azioni di dipendenza .

scenari delle relazione

In Azure Batch è possibile usare tre scenari di relazioni tra attività di base, ovvero uno-a-uno, uno-a-molti e la relazione tra intervalli di ID. Questi tre scenari possono essere combinati per fornire un quarto scenario: molti-a-molti.

Scenario Esempio Illustrazione
Uno-a-uno taskBdipendedall'attivitàA

attivitàB non verrà pianificata per l'esecuzione finché l'attivitàA non è stata completata correttamente

Diagramma che mostra lo scenario di dipendenza da uno a uno.
Uno-a-molti taskC dipende sia dall'attivitàA chedall'taskBC non verrà pianificata per l'esecuzione fino a quando sia l'attivitàA che l'attivitàB

non sono state completate correttamente

Diagramma che mostra lo scenario di dipendenza di attività uno-a-molti.
Intervallo di ID attività taskD dipende da un intervallo di attività taskD non sarà pianificato per l'esecuzione fino a quando le attività

con ID 1-10 sono state completate correttamente

Diagramma che mostra lo scenario di dipendenza dell'attività intervallo ID attività.

Suggerimento

È possibile creare relazioni molti-a-molti, ad esempio relazioni in cui le attività C, D, E e F dipendono dalle attività A e B. Questo tipo di relazione risulta utile, ad esempio, negli scenari di pre-elaborazione parallelizzata, in cui le attività downstream dipendono dall'output di più attività upstream.

Negli esempi di questa sezione un'attività dipendente viene eseguita solo dopo che le attività padre vengono completate correttamente. Questo comportamento è quello predefinito per un'attività dipendente. È possibile eseguire un'attività dipendente dopo che un'attività padre ha esito negativo specificando un'azione di dipendenza per eseguire l'override del comportamento predefinito.

Uno-a-uno

In una relazione uno-a-uno un'attività dipende dal corretto completamento di una sola attività padre. Per creare la dipendenza, specificare un singolo ID attività al metodo statico TaskDependencies.OnId quando si popola la proprietà CloudTask.DependsOn .

// Task 'taskA' doesn't depend on any other tasks
new CloudTask("taskA", "cmd.exe /c echo taskA"),

// Task 'taskB' depends on completion of task 'taskA'
new CloudTask("taskB", "cmd.exe /c echo taskB")
{
    DependsOn = TaskDependencies.OnId("taskA")
},

Uno-a-molti

In una relazione uno-a-molti un'attività dipende dal completamento di più attività padre. Per creare la dipendenza, fornire una raccolta di ID attività specifici al metodo statico TaskDependencies.OnIds quando si popola la proprietà CloudTask.DependsOn .

// 'Rain' and 'Sun' don't depend on any other tasks
new CloudTask("Rain", "cmd.exe /c echo Rain"),
new CloudTask("Sun", "cmd.exe /c echo Sun"),

// Task 'Flowers' depends on completion of both 'Rain' and 'Sun'
// before it is run.
new CloudTask("Flowers", "cmd.exe /c echo Flowers")
{
    DependsOn = TaskDependencies.OnIds("Rain", "Sun")
},

Importante

La creazione dell'attività dipendente avrà esito negativo se la lunghezza combinata degli ID attività padre è maggiore di 64000 caratteri. Per specificare un numero elevato di attività padre, è consigliabile usare invece un intervallo DI ID attività.

Intervallo di ID attività

In una dipendenza da un intervallo di attività padre, un'attività dipende dal completamento delle attività i cui ID si trovano all'interno di un intervallo specificato.

Per creare la dipendenza, specificare gli ID attività prima e ultima nell'intervallo al metodo statico TaskDependencies.OnIdRange quando si popola la proprietà CloudTask.DependsOn .

Importante

Quando si usano intervalli di ID attività per le dipendenze, verranno selezionate solo le attività con ID che rappresentano valori interi. Ad esempio, l'intervallo 1..10 seleziona attività 3 e 7, ma non 5flamingoes.

Gli zero iniziali non sono significativi quando si valutano le dipendenze dell'intervallo, quindi le attività con identificatori 404 di stringa e 004 saranno tutte all'interno dell'intervallo, poiché verranno considerate tutte come attività 4, la prima da completare soddisfa la dipendenza.

Per l'esecuzione dell'attività dipendente, ogni attività nell'intervallo deve soddisfare la dipendenza, completando correttamente o completando un errore mappato a un'azione di dipendenza impostata su Soddisfa.

// Tasks 1, 2, and 3 don't depend on any other tasks. Because
// we will be using them for a task range dependency, we must
// specify string representations of integers as their ids.
new CloudTask("1", "cmd.exe /c echo 1"),
new CloudTask("2", "cmd.exe /c echo 2"),
new CloudTask("3", "cmd.exe /c echo 3"),

// Task 4 depends on a range of tasks, 1 through 3
new CloudTask("4", "cmd.exe /c echo 4")
{
    // To use a range of tasks, their ids must be integer values.
    // Note that we pass integers as parameters to TaskIdRange,
    // but their ids (above) are string representations of the ids.
    DependsOn = TaskDependencies.OnIdRange(1, 3)
},

Azioni di dipendenza

Per impostazione predefinita, un'attività o un set di attività dipendenti vengono eseguite solo dopo il corretto completamento di un'attività padre. In alcuni scenari potrebbe essere necessario eseguire attività dipendenti anche se l'attività padre non riesce. È possibile eseguire l'override del comportamento predefinito specificando un'azione di dipendenza che indica se un'attività dipendente è idonea per l'esecuzione.

Si supponga, ad esempio, un'attività dipendente in attesa di dati dal completamento dell'attività upstream. Se l'attività upstream non riesce, l'attività dipendente potrebbe comunque essere eseguita usando dati meno recenti. In questo caso, un'azione di dipendenza può specificare che l'attività dipendente è idonea per l'esecuzione nonostante l'errore dell'attività padre.

Un'azione di dipendenza è basata su una condizione di uscita per l'attività padre. È possibile specificare un'azione di dipendenza per una delle condizioni di uscita seguenti:

  • Quando si verifica un errore di pre-elaborazione.
  • Quando si verifica un errore di caricamento dei file. Se l'attività si chiude con un codice di uscita specificato tramite exitCodes o exitCodeRanges e quindi si verifica un errore di caricamento dei file, l'azione specificata dal codice di uscita ha la precedenza.
  • Quando l'attività termina con un codice di uscita definito dalla proprietà ExitCodes.
  • Quando l'attività termina con un codice di uscita compreso in un intervallo specificato dalla proprietà ExitCodeRanges.
  • Il caso predefinito, ovvero se l'attività si chiude con un codice di uscita non definito da ExitCodes o ExitCodeRanges oppure se l'attività si chiude con un errore di pre-elaborazione e la proprietà PreProcessingError non è stata configurata o se l'attività ha esito negativo con un errore di caricamento dei file e la proprietà FileUploadError non è stata configurata.

Per .NET, queste condizioni vengono definite come proprietà della classe ExitConditions .

Per specificare un'azione di dipendenza, impostare la proprietà ExitOptions.DependencyAction per la condizione di uscita su una delle opzioni seguenti:

  • Soddisfa: indica che le attività dipendenti sono idonee per l'esecuzione se l'attività padre termina con un errore specificato.
  • Blocco: indica che le attività dipendenti non sono idonee per l'esecuzione.

L'impostazione predefinita per la proprietà DependencyAction è Satisfy per il codice di uscita 0 e Block per tutte le altre condizioni di uscita.

Il frammento di codice seguente imposta la proprietà DependencyAction per un'attività padre. Se l'attività padre termina con un errore di pre-elaborazione o con i codici di errore specificati, l'attività dipendente viene bloccata. Se l'attività padre termina con qualsiasi altro errore diverso da zero, l'attività dipendente è idonea per l'esecuzione.

// Task A is the parent task.
new CloudTask("A", "cmd.exe /c echo A")
{
    // Specify exit conditions for task A and their dependency actions.
    ExitConditions = new ExitConditions
    {
        // If task A exits with a pre-processing error, block any downstream tasks (in this example, task B).
        PreProcessingError = new ExitOptions
        {
            DependencyAction = DependencyAction.Block
        },
        // If task A exits with the specified error codes, block any downstream tasks (in this example, task B).
        ExitCodes = new List<ExitCodeMapping>
        {
            new ExitCodeMapping(10, new ExitOptions() { DependencyAction = DependencyAction.Block }),
            new ExitCodeMapping(20, new ExitOptions() { DependencyAction = DependencyAction.Block })
        },
        // If task A succeeds or fails with any other error, any downstream tasks become eligible to run 
        // (in this example, task B).
        Default = new ExitOptions
        {
            DependencyAction = DependencyAction.Satisfy
        }
    }
},
// Task B depends on task A. Whether it becomes eligible to run depends on how task A exits.
new CloudTask("B", "cmd.exe /c echo B")
{
    DependsOn = TaskDependencies.OnId("A")
},

Esempio di codice

Il progetto di esempio TaskDependencies in GitHub illustra:

  • Come abilitare la dipendenza dell'attività da un processo.
  • Come creare attività che dipendono da altre attività.
  • Come eseguire queste attività in un pool di nodi di calcolo.

Passaggi successivi