---
title: "Task chaining"
slug: "task-chaining"
abstract: ""
---
# Task chaining

You can determine the execution order of a set of tasks by passing in a list of prerequisite task IDs when you register each task. In the following example, task #2 and task #3 are registered with an array of prerequisite task IDs.

```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Sitecore.Processing.Engine;
using Sitecore.Processing.Engine.Abstractions;
using Sitecore.Processing.Tasks.Options.DataSources.DataExtraction;
using Sitecore.XConnect;

namespace Sitecore.Docs.Examples
{
    public class DocTaskManager
    {
        public async Task Sample()
        {
            TaskManager taskManager = null;

            // Task #1
            Guid distributedTaskId = await taskManager.RegisterDistributedTaskAsync(
                new ContactDataSourceOptionsDictionary(new ContactExpandOptions(new string[] { "TestFacetKey" }), 300, 300),
                new DistributedWorkerOptionsDictionary("Sitecore.Documentation.SampleDistributedWorker", new Dictionary<string, string> { { "testkey", "testvalue" } }),
                null,
                TimeSpan.MaxValue);

            // Task #2
            Guid deferredTaskId = await taskManager.RegisterDeferredTaskAsync(
                new DeferredWorkerOptionsDictionary("Sitecore.Documentation.SampleDeferredWorker",
                new Dictionary<string, string>() { { "testkey", "testvalue" } }),
                new Guid[] { distributedTaskId }, // Will not run before task #1 is complete
                TimeSpan.MaxValue);

            // Task #3
            Guid deferredTaskId = await taskManager.RegisterDeferredTaskAsync(
                new DeferredWorkerOptionsDictionary("Sitecore.Documentation.SecondSampleDeferredWorker",
                new Dictionary<string, string>() { { "testkey", "testvalue" } }),
                new Guid[] { deferredTaskId }, // Will not run before task #2 is complete
                TimeSpan.MaxValue);
        }
    }
}
```

## Chaining projection and merge

When you register a data projection task, you must register a dependent merge task that executes when data projection is complete.

Data projection is performed by a distributed worker (`ProjectionWorker`). Each worker projects data into its own temporary table in the Cortex Processing Engine Storage database, which means that ten workers will produce ten separate tables. The merge worker (`MergeWorker`) combines the data into a single table and deletes the temporary tables.

> [!tip]
> The `RegisterModelTrainingTaskChainAsync()` method in the `Sitecore.Processing.Engine.Abstractions.TaskManagerExtensions` extension class creates a chain of three tasks, including data projection and merge.