Tworzenie zależności zadań w celu uruchamiania zadań, które zależą od innych zadań

Zależności zadań podrzędnych usługi Batch umożliwiają tworzenie zadań zaplanowanych do wykonania w węzłach obliczeniowych po zakończeniu co najmniej jednego zadania nadrzędnego. Można na przykład utworzyć zadanie, które renderuje każdą ramkę filmu 3D z oddzielnymi zadaniami równoległymi. Ostatnie zadanie scala wyrenderowane klatki w kompletny film dopiero po pomyślnym wyrenderowaniu wszystkich klatek. Innymi słowy, ostateczne zadanie jest zależne od poprzednich zadań nadrzędnych.

Niektóre scenariusze, w których zależności zadań są przydatne, obejmują:

  • Obciążenia w stylu MapReduce w chmurze.
  • Zadania, których zadania przetwarzania danych można wyrazić jako skierowany graf acykliczny (DAG).
  • Procesy prerenderingu i po renderowaniu, w których każde zadanie musi zostać ukończone przed rozpoczęciem następnego zadania.
  • Każde inne zadanie, w którym podrzędne zadania zależą od danych wyjściowych zadań nadrzędnych.

Domyślnie zadania zależne są zaplanowane do wykonania dopiero po pomyślnym zakończeniu zadania nadrzędnego. Opcjonalnie można określić akcję zależności, aby zastąpić domyślne zachowanie i uruchomić zadanie zależne, nawet jeśli zadanie nadrzędne zakończy się niepowodzeniem.

W tym artykule omówiono sposób konfigurowania zależności zadań przy użyciu biblioteki Batch .NET. Najpierw pokażemy, jak włączyć zależności między zadaniami dla swoich zadań, a następnie zademonstrujemy, jak skonfigurować zadanie z zależnościami. Opisujemy również, jak określić działanie zależności, aby uruchamiać zadania zależne w przypadku niepowodzenia zadania nadrzędnego. Na koniec omówimy scenariusze zależności obsługiwane przez usługę Batch.

Włącz zależności zadań

Aby używać zależności zadań w aplikacji usługi Batch, należy najpierw skonfigurować zadanie do korzystania z zależności zadań. W usłudze Batch platformy .NET włącz tę opcję w obiekcie BatchJobCreateOptions, ustawiając jego właściwość UsesTaskDependencies na true:

BatchJobCreateOptions unboundJob = new BatchJobCreateOptions("job001", new BatchPoolInfo() { PoolId = "pool001" })
{
    // IMPORTANT: This is REQUIRED for using task dependencies.
    UsesTaskDependencies = true
};
await batchClient.CreateJobAsync(unboundJob);

W poprzednim fragmencie kodu "batchClient" jest wystąpieniem klasy BatchClient .

Tworzenie zadań zależnych

Aby utworzyć zadanie, które zależy od ukończenia co najmniej jednego zadania nadrzędnego, można określić, że zadanie "zależy od" innych zadań. W usłudze Batch platformy .NET skonfiguruj właściwość BatchTaskCreateOptions.DependsOn za pomocą wystąpienia klasy BatchTaskDependencies:

// Task 'Flowers' depends on completion of both 'Rain' and 'Sun'
// before it is run.
BatchTaskCreateOptions flowers = new BatchTaskCreateOptions("Flowers", "cmd.exe /c echo Flowers")
{
    DependsOn = new BatchTaskDependencies()
    {
        TaskIds = { "Rain", "Sun" }
    }
};

Ten fragment kodu tworzy zależne zadanie o identyfikatorze zadania "Kwiaty". Zadanie "Kwiaty" zależy od zadań "Deszcz" i "Słońce". Zadanie "Kwiaty" zostanie zaplanowane do uruchomienia w węźle obliczeniowym dopiero po pomyślnym ukończeniu zadań "Deszcz" i "Słońce".

Uwaga

Domyślnie zadanie jest uznawane za ukończone pomyślnie, gdy znajduje się w stanie ukończonym, a jego kod zakończenia to 0. W .NET usługi Batch oznacza to, że wartość właściwości BatchTask.State jest Completed, a wartość właściwości BatchTask BatchTaskExecutionInfo.ExitCode jest 0. Aby dowiedzieć się, jak to zmienić, zobacz sekcję Akcje zależności.

Scenariusze zależności

Istnieją trzy podstawowe scenariusze zależności zadań, których można użyć w usłudze Azure Batch: zależność jeden do jednego, jeden do wielu i zakres identyfikatorów zadań. Te trzy scenariusze można połączyć, aby uzyskać czwarty scenariusz: wiele-do-wielu.

Scenariusz Przykład Ilustracja
Jeden do jednego zadanieB zależy od zadaniaA

zadanieB nie zostanie zaplanowane do uruchomienia, dopóki zadanieA nie zostanie pomyślnie ukończone

Diagram przedstawia scenariusz zależności zadań 1:1.
Jeden do wielu ZadanieC zależy zarówno od zadaniaA, jak i zadaniaB

zadanieC nie zostanie zaplanowane do wykonania, dopóki zadanieA i zadanieB nie zostaną ukończone pomyślnie

Diagram przedstawia scenariusz zależności jednego zadania od wielu.
Zakres identyfikatorów zadań taskD zależy od szeregu zadań.

taskD nie zostanie zaplanowany do wykonania, dopóki zadania z identyfikatorami 1 do 10 nie zostaną ukończone pomyślnie.

Diagram przedstawiający scenariusz zależności zadań w zakresie identyfikatorów zadań.

Wskazówka

Można tworzyć relacje wiele-do-wielu, w których zadania C, D, E i F każde z osobna zależą od zadań A i B. Jest to przydatne na przykład w scenariuszach równoległego przetwarzania wstępnego, w których zadania podrzędne zależą od wyników wielu zadań nadrzędnych.

W przykładach w tej sekcji zależne zadanie jest uruchamiane dopiero po pomyślnym zakończeniu zadań nadrzędnych. Jest to domyślne zachowanie dla zadania zależnego w systemie. Zadanie zależne można uruchomić po niepowodzeniu zadania nadrzędnego, określając akcję zależności, aby zastąpić domyślne zachowanie.

Jeden do jednego

W relacji jeden do jednego zadanie zależy od pomyślnego zakończenia jednego zadania nadrzędnego. Aby utworzyć zależność, ustaw właściwość BatchTaskDependencies.TaskIds z pojedynczym identyfikatorem zadania podczas wypełniania właściwości BatchTaskCreateOptions.DependsOn .

IList<BatchTaskCreateOptions> tasks = new List<BatchTaskCreateOptions>
{
    // Task 'taskA' doesn't depend on any other tasks
    new BatchTaskCreateOptions("taskA", "cmd.exe /c echo taskA"),

    // Task 'taskB' depends on completion of task 'taskA'
    new BatchTaskCreateOptions("taskB", "cmd.exe /c echo taskB")
    {
        DependsOn = new BatchTaskDependencies() { TaskIds = { "taskA" } }
    },
};

Jeden-do-wielu

W relacji jeden do wielu zadanie zależy od ukończenia wielu zadań nadrzędnych. Aby utworzyć zależność, po wypełnieniu właściwości BatchTaskDependencies.TaskIds identyfikatorami zadań nadrzędnych wypełnij właściwość BatchTaskCreateOptions.DependsOn .

IList<BatchTaskCreateOptions> tasks = new List<BatchTaskCreateOptions>
{
    // 'Rain' and 'Sun' don't depend on any other tasks
    new BatchTaskCreateOptions("Rain", "cmd.exe /c echo Rain"),
    new BatchTaskCreateOptions("Sun", "cmd.exe /c echo Sun"),

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

Ważne

Tworzenie zadania zależnego kończy się niepowodzeniem, jeśli łączna długość identyfikatorów zadań nadrzędnych jest większa niż 64 000 znaków. Aby określić dużą liczbę zadań nadrzędnych, rozważ zamiast tego użycie zakresu identyfikatorów zadań.

Zakres identyfikatorów zadań

W przypadku zależności od zakresu zadań nadrzędnych zadanie zależy od ukończenia zadań, których identyfikatory mieszczą się w zakresie, który określisz.

Aby utworzyć zależność, wypełnij właściwość BatchTaskDependencies.TaskIdRanges za pomocą elementu BatchTaskIdRange po wypełnieniu właściwości BatchTaskCreateOptions.DependsOn .

Ważne

W przypadku używania zakresów identyfikatorów zadań dla zależności wybierane są tylko te zadania, których identyfikatory reprezentują wartości całkowite. Na przykład zakres 1..10 wybiera zadania 3 i 7, ale nie 5flamingoes.

Wiodące zera nie są istotne podczas oceniania zależności zakresu, więc zadania z identyfikatorami ciągów 4, 04i 004 znajdują się w zakresie, ponieważ wszystkie są traktowane jako zadanie 4, pierwszy do ukończenia spełnia zależność.

Aby zadanie zależne mogło zostać uruchomione, każde zadanie w tym zakresie musi spełnić warunek zależności, kończąc się pomyślnie albo kończąc się niepowodzeniem, którego mapowanie wskazuje na akcję zależności ustawioną na Satisfy.

IList<BatchTaskCreateOptions> tasks = new List<BatchTaskCreateOptions>
{
    // 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 BatchTaskCreateOptions("1", "cmd.exe /c echo 1"),
    new BatchTaskCreateOptions("2", "cmd.exe /c echo 2"),
    new BatchTaskCreateOptions("3", "cmd.exe /c echo 3"),

    // Task 4 depends on a range of tasks, 1 through 3
    new BatchTaskCreateOptions("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 BatchTaskIdRange,
        // but their ids (above) are string representations of the ids.
        DependsOn = new BatchTaskDependencies()
        {
            TaskIdRanges = { new BatchTaskIdRange(1, 3) }
        }
    },
};

Działania zależności

Domyślnie zależne zadanie lub zestaw zadań są uruchamiane tylko po pomyślnym ukończeniu zadania nadrzędnego. W niektórych scenariuszach możesz chcieć uruchamiać zadania zależne, nawet jeśli zadanie nadrzędne zakończy się niepowodzeniem. Domyślne zachowanie można zastąpić, określając akcję zależności, która wskazuje, czy zadanie zależne kwalifikuje się do uruchomienia.

Załóżmy na przykład, że zależne zadanie oczekuje na dane od ukończenia zadania nadrzędnego. Jeśli zadanie nadrzędne zakończy się niepowodzeniem, zależne zadanie może nadal być w stanie uruchomić przy użyciu starszych danych. W takim przypadku akcja zależności może określać, że zależne zadanie kwalifikuje się do uruchomienia pomimo niepowodzenia zadania nadrzędnego.

Działanie zależne opiera się na warunku zakończenia zadania nadrzędnego. Możesz określić działanie zależne dla dowolnego z poniższych warunków zakończenia:

  • Za każdym razem, gdy wystąpi błąd przetwarzania wstępnego.
  • Za każdym razem, gdy wystąpi błąd przesyłania pliku. Jeśli zadanie kończy się kodem zakończenia określonym w exitCodes lub exitCodeRanges, a następnie wystąpi błąd przekazywania pliku, pierwszeństwo ma akcja określona przez kod zakończenia.
  • Za każdym razem, gdy zadanie zakończy się z kodem zakończenia zdefiniowanym przez atrybut ExitCodes.
  • Za każdym razem, gdy zadanie kończy się z kodem zakończenia należącym do zakresu wyznaczonego przez właściwość ExitCodeRanges.
  • Domyślny przypadek, jeśli zadanie kończy działanie z kodem zakończenia, który nie jest zdefiniowany przez ExitCodes lub ExitCodeRanges, lub jeśli zadanie kończy się z błędem przetwarzania wstępnego i właściwość PreProcessingError nie jest ustawiona lub jeśli zadanie zakończy się niepowodzeniem z błędem przekazywania pliku i właściwość FileUploadError nie jest ustawiona.

W przypadku platformy .NET te warunki są definiowane jako właściwości klasy ExitConditions .

Aby określić akcję zależności, ustaw właściwość ExitOptions.DependencyAction dla warunku zakończenia na jedną z następujących opcji:

  • Spełnij: wskazuje, że zadania zależne mogą zostać uruchomione, jeśli zadanie nadrzędne zakończy się określonym błędem.
  • Blokuj: wskazuje, że zadania zależne nie kwalifikują się do uruchomienia.

Ustawieniem domyślnym właściwości DependencyAction jest Spełnianie dla kodu zakończenia 0 i Blokuj dla wszystkich innych warunków zakończenia.

Poniższy fragment kodu ustawia właściwość DependencyAction dla zadania nadrzędnego. Jeśli zadanie nadrzędne kończy się z błędem przetwarzania wstępnego lub z określonymi kodami błędów, zadanie zależne jest blokowane. Jeśli zadanie nadrzędne kończy działanie z jakimkolwiek innym błędem niezerowym, zależne zadanie kwalifikuje się do uruchomienia.

IList<BatchTaskCreateOptions> tasks = new List<BatchTaskCreateOptions>
{
    // Task A is the parent task.
    new BatchTaskCreateOptions("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 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).
            DefaultExitOptions = new ExitOptions()
            {
                DependencyAction = DependencyAction.Satisfy
            }
        }
    },
    // Task B depends on task A. Whether it becomes eligible to run depends on how task A exits.
    new BatchTaskCreateOptions("B", "cmd.exe /c echo B")
    {
        DependsOn = new BatchTaskDependencies() { TaskIds = { "A" } }
    },
};

Przykład kodu

Przykładowy projekt TaskDependencies w usłudze GitHub pokazuje:

  • Jak włączyć zależność zadania od zadania.
  • Jak tworzyć zadania zależne od innych zadań.
  • Jak wykonywać te zadania w puli węzłów obliczeniowych.

Następne kroki