タスクの依存関係を作成して、他のタスクに依存するタスクを実行する

Batch のタスク依存関係を使用し、コンピューティング ノードで 1 つ以上の親タスクが完了した後に実行されるようにスケジューリングされたタスクを作成します。 たとえば、並列実行される複数の独立したタスクを使って 3D ムービーの各フレームをレンダリングするジョブを作成できます。 最後のタスクでは、すべてのフレームが正常にレンダリングされた後にのみ、そのレンダリング済みのフレームをマージしてムービーを完成させます。 つまり、最後のタスクは、その前の親タスクに依存します。

タスクの依存関係は、たとえば次のようなシナリオで役立ちます。

  • クラウドでの MapReduce 形式のワークロード。
  • 有向非巡回グラフ (DAG) としてデータ処理タスクを表すことのできるジョブ。
  • 各タスクが次のタスクの開始前に完了している必要がある、レンダリング前およびレンダリング後プロセス。
  • 下流のタスクが上流タスクの出力に依存する、その他すべてのジョブ。

既定では、依存タスクは、親タスクが正常に完了した後にのみ実行されるようにスケジューリングされます。 既定の動作をオーバーライドし、親タスクが失敗しても依存タスクを実行する、依存関係アクションを任意で指定できます。

この記事では、Batch .NET ライブラリを使用したタスクの依存関係の構成方法について説明します。 まず、ジョブでタスクの依存関係を有効にする方法を説明した後、依存関係を伴うタスクを構成する方法を紹介します。 親が失敗した場合に依存タスクを実行する、依存関係アクションを指定する方法についても説明します。 最後に、Batch でサポートされる 依存関係のシナリオ について取り上げます。

タスクの依存関係を有効にする

Batch アプリケーションでタスクの依存関係を使用するには、まず、タスクの依存関係を使用するジョブを構成する必要があります。 Batch .NET では、CloudJobUsesTaskDependencies プロパティを true に設定することによって有効にします。

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

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

前のコード スニペットでは、"batchClient" は、BatchClient クラスのインスタンスです。

依存タスクの作成

1 つ以上の親タスクの完了に依存するタスクを作成するには、タスクが他のタスクに "依存" するよう指定します。 Batch .NET では、TaskDependencies クラスのインスタンスを使って CloudTask.DependsOn プロパティを構成します。

// 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")
},

このコード スニペットでは、"Flowers" というタスク ID の依存タスクを作成しています。 "Flowers" タスクは "Rain" タスクと "Sun" タスクに依存します。 "Flowers" タスクは、"Rain" タスクと "Sun" タスクが正常に完了した後にのみコンピューティング ノードで実行されるようにスケジューリングされます。

注意

既定では、タスクは completed 状態になり、その終了コードが 0 であるときに正常に完了したと見なされます。 Batch .NET では、CloudTask.State プロパティの値が Completed で、なおかつ CloudTask の TaskExecutionInformation.ExitCode プロパティの値が 0 であることを意味します。 これを変更する方法については、「依存関係アクション」セクションを参照してください。

依存関係のシナリオ

Azure Batch で利用できる基本的なタスクの依存関係には、一対一、一対多、タスク ID 範囲という 3 つのシナリオがあります。 これら 3 つのシナリオを組み合わせることで、第 4 のシナリオ (多対多) を実現することもできます。

シナリオ       
一対一 taskBtaskA に依存

taskB は、taskA が正常に完了するまで実行されないようにスケジューリングされる

一対一のタスク依存関係シナリオを示す図。
[一対多] taskCtaskAtaskB の両方に依存

taskC は、taskAtaskB の両方が正常に完了するまで実行されないようにスケジューリングされる

一対多のタスク依存関係シナリオを示す図。
タスク ID の範囲 taskD は、一連のタスク範囲に依存

taskD は、ID 110 のタスクが正常に完了するまで実行されないようにスケジューリングされる

タスク ID 範囲のタスク依存関係シナリオを示す図。

ヒント

タスク C、D、E、F がそれぞれタスク A と B に依存するような 多対多 の関係を作成できます。たとえば下流の複数のタスクが上流にある複数のタスクの出力に依存するような、前処理を並列実行する状況で有効活用できます。

このセクションの例では、依存タスクは親タスクが正常に完了した後にのみ実行されます。 この動作は、依存タスクの既定の動作です。 既定の動作をオーバーライドする依存関係アクションを指定すると、親タスクが失敗した後に依存タスクを実行できます。

一対一

一対一の依存関係では、タスクは 1 つの親タスクの正常な完了に依存します。 この依存関係を作成するには、CloudTask.DependsOn プロパティに値を設定する際、TaskDependencies.OnId 静的メソッドに 1 つのタスク ID を渡します。

// 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")
},

一対多

一対多の依存関係では、タスクは複数の親タスクの完了に依存します。 この依存関係を作成するには、CloudTask.DependsOn プロパティに値を設定する際、TaskDependencies.OnIds 静的メソッドに特定のタスク ID のコレクションを渡します。

// '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")
},

重要

親タスク ID の合計長が 64000 文字を超える場合、依存タスクの作成は失敗します。 多数の親タスクを指定するには、代わりにタスク ID 範囲の使用を検討してください。

タスク ID の範囲

親タスクの範囲への依存関係では、タスクは、指定した特定の範囲内に ID があるタスクの完了に依存します。

この依存関係を作成するには、CloudTask.DependsOn プロパティに値を設定する際に、範囲の最初のタスク ID と最後のタスク ID を TaskDependencies.OnIdRange 静的メソッドに指定します。

重要

依存関係にタスク ID の範囲を使用した場合、その範囲によって選択されるのは、整数値を表す ID を持つタスクだけです。 たとえば、範囲 1..10 ではタスク 37 が選択されますが、5flamingoes は選択されません。

範囲の依存関係を評価するときに先頭のゼロは重要ではないため、404004 の文字列識別子を持つタスクはすべて範囲 "" になります。それらはすべてタスク 4 として扱われるため、最初に完了したものが依存関係を満たします。

依存タスクが実行するためには、範囲内のすべてのタスクが、正常に完了するか、または Satisfy に設定された依存関係アクションに指定されているエラーで終了することによって、依存関係を満たしている必要があります。

// 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)
},

依存関係アクション

既定では、依存タスクまたは一連の依存タスク は、親タスクが正常に完了した後にのみ実行されます。 シナリオによっては、親タスクが失敗した後でも依存タスクを実行したい場合があります。 依存タスクが実行対象かどうかを示す "依存関係アクション" を指定することで、既定の動作をオーバーライドできます。

たとえば、依存タスクが、上流タスクの完了によって得られるデータを待機しているとします。 上流タスクが失敗しても、古いデータを使用して依存タスクを実行できる場合があります。 その場合は、依存関係アクションで、親タスクの失敗にかかわらずタスクを実行対象にするよう指定できます。

依存関係アクションは、親タスクの終了条件に基づきます。 次のどの終了条件に対しても依存関係アクションを指定できます。

  • 前処理エラーが発生したとき。
  • ファイルのアップロード エラーが発生したとき。 exitCodes または exitCodeRanges で指定された終了コードでタスクが終了し、その後ファイルのアップロード エラーが発生した場合、その終了コードにより指定されたアクションが優先されます。
  • ExitCodes プロパティで定義された終了コードでタスクが終了したとき。
  • ExitCodeRanges プロパティで定義された範囲内の終了コードでタスクが終了したとき。
  • 既定のケースで、ExitCodes および ExitCodeRanges で定義されていない終了コードでタスクが終了した、または前処理エラーでタスクが終了し、PreProcessingError プロパティが設定されていない、またはファイルのアップロード エラーでタスクが失敗し、FileUploadError プロパティが設定されていない場合。

.NET の場合、これらの条件は ExitConditions クラスのプロパティとして定義されます。

依存関係アクションを指定するには、終了条件の ExitOptions.DependencyAction プロパティを次のいずれかに設定します。

  • Satisfy:指定したエラーで親タスクが終了した場合に依存タスクが実行対象になります。
  • ブロック: 依存タスクは実行できないことを示します。

DependencyAction プロパティの既定の設定は、終了コード 0 に対しては Satisfy、その他のすべての終了条件に対しては Block です。

次のコード スニペットでは、親タスクの DependencyAction プロパティを設定します。 親タスクが前処理エラーで終了した場合、または指定したエラー コードで終了した場合は、依存タスクがブロックされます。 親タスクがその他の 0 以外のエラーで終了した場合は、依存タスクが実行対象となります。

// 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")
},

コード サンプル

GitHub の TaskDependencies サンプル プロジェクトは次を示します。

  • ジョブでタスクの依存関係を有効にする方法。
  • 他のタスクに依存するタスクを作成する方法。
  • コンピューティング ノードのプールでそれらのタスクを実行する方法

次のステップ