Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,19 @@ public class MyHandler : TaskRequestHandler<MyRequest, MyResponse>
}
```

#### Run context (Maestro)

Maestro can start a workflow run with an execution context: key/value pairs such as the tenant
and user the run is for. It sends the context with every polled task, and the workflow cannot
change it, so read identity from there rather than from the task input:

```csharp
var workspaceId = _context.Context.TryGetValue("workspaceId", out var id) ? id : null;
```

Set it when starting a run with `StartWorkflowRequest.Context`. Conductor sends no context, so
against Conductor `Context` is empty and the field is left out of start requests.

## Patterns Package

Additional built-in tasks and utilities:
Expand Down
2 changes: 1 addition & 1 deletion src/ConductorSharp.Client/ConductorSharp.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Authors>Codaxy</Authors>
<Company>Codaxy</Company>
<PackageId>ConductorSharp.Client</PackageId>
<Version>4.4.1</Version>
<Version>4.5.0</Version>
<Description>Client library for Netflix Conductor, with some additional quality of life features.</Description>
<RepositoryUrl>https://github.com/codaxy/conductor-sharp</RepositoryUrl>
<PackageTags>netflix;conductor</PackageTags>
Expand Down
40 changes: 40 additions & 0 deletions src/ConductorSharp.Client/Generated/ExecutionContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Newtonsoft.Json;

namespace ConductorSharp.Client.Generated
{
// The execution context is a Maestro extension of the Conductor API: key/value pairs a workflow
// run is started with, kept unchanged for the life of the run and inherited by its sub-workflows.
// Conductor neither sends nor reads it. These partials live outside Models.cs so regenerating the
// models does not drop them.

public partial class Task
{
/// <summary>
/// Execution context of the workflow run this task belongs to, as Maestro sends it with a
/// polled task. Null from Conductor.
/// </summary>
[JsonProperty("context", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
public IDictionary<string, string>? Context { get; set; }
}

public partial class Workflow
{
/// <summary>
/// Execution context the run was started with, as Maestro reports it on a workflow read.
/// Null from Conductor.
/// </summary>
[JsonProperty("context", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
public IDictionary<string, string>? Context { get; set; }
}

public partial class StartWorkflowRequest
{
/// <summary>
/// Execution context to start the run with. Maestro stores it with the run, hands it to every
/// task and sub-workflow, and never lets the workflow change it. Omitted from the request when
/// null, so a start against Conductor is unchanged.
/// </summary>
[JsonProperty("context", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
public IDictionary<string, string>? Context { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/ConductorSharp.Engine/ConductorSharp.Engine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Authors>Codaxy</Authors>
<Company>Codaxy</Company>
<PackageId>ConductorSharp.Engine</PackageId>
<Version>4.4.1</Version>
<Version>4.5.0</Version>
<Description>Client library for Netflix Conductor, with some additional quality of life features.</Description>
<RepositoryUrl>https://github.com/codaxy/conductor-sharp</RepositoryUrl>
<PackageTags>netflix;conductor</PackageTags>
Expand Down
7 changes: 7 additions & 0 deletions src/ConductorSharp.Engine/ExecutionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ private async Task PollAndHandle(TaskToWorker scheduledWorker, CancellationToken
return;
}

// A transport other than HTTP may answer "no task" with null instead of a 204, as
// Maestro's in-process transport does. Handling it here keeps that from surfacing as a
// NullReferenceException in a poll nobody awaits.
if (pollResponse == null)
return;

await ProcessPolledTask(pollResponse, workerId, scheduledWorker, cancellationToken);
}

Expand Down Expand Up @@ -200,6 +206,7 @@ CancellationToken cancellationToken
context.TaskReferenceName = pollResponse.ReferenceTaskName;
context.WorkflowId = pollResponse.WorkflowInstanceId;
context.CorrelationId = pollResponse.CorrelationId;
context.Context = ConductorSharpExecutionContext.CopyContext(pollResponse.Context);
context.TaskId = pollResponse.TaskId;
context.WorkerId = workerId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ private async Task PollAndHandle(TaskToWorker scheduledWorker, CancellationToken
return;
}

// A transport other than HTTP may answer "no task" with null instead of a 204, as
// Maestro's in-process transport does. Handling it here keeps that from surfacing as a
// NullReferenceException in a poll nobody awaits.
if (pollResponse == null)
return;

await ProcessPolledTask(pollResponse, workerId, scheduledWorker, cancellationToken);
}

Expand Down Expand Up @@ -209,6 +215,7 @@ CancellationToken cancellationToken
context.TaskReferenceName = pollResponse.ReferenceTaskName;
context.WorkflowId = pollResponse.WorkflowInstanceId;
context.CorrelationId = pollResponse.CorrelationId;
context.Context = ConductorSharpExecutionContext.CopyContext(pollResponse.Context);
context.TaskId = pollResponse.TaskId;
context.WorkerId = workerId;
}
Expand Down
29 changes: 29 additions & 0 deletions src/ConductorSharp.Engine/Util/ConductorSharpExecutionContext.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,46 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;

namespace ConductorSharp.Engine.Util
{
public class ConductorSharpExecutionContext
{
private static readonly IReadOnlyDictionary<string, string> NoContext = new ReadOnlyDictionary<string, string>(
new Dictionary<string, string>()
);

public string WorkflowName { get; set; }
public string WorkflowId { get; set; }
public string TaskName { get; set; }
public string TaskId { get; set; }
public string TaskReferenceName { get; set; }
public string CorrelationId { get; set; }
public string WorkerId { get; set; }

/// <summary>
/// The execution context of the workflow run the task belongs to: key/value pairs the run was
/// started with, such as the tenant and user it runs for. Maestro sends it with every polled
/// task. Conductor sends none, and then this is empty.
/// </summary>
/// <remarks>
/// Read identity from here rather than from the task's input. Maestro does not let the
/// workflow change the context after the start, while the input is whatever the workflow
/// definition puts there.
/// </remarks>
public IReadOnlyDictionary<string, string> Context { get; set; } = NoContext;

/// <summary>
/// Copies the context from a polled task, so a handler cannot change what the next handler
/// sees by writing to the task's dictionary.
/// </summary>
internal static IReadOnlyDictionary<string, string> CopyContext(IDictionary<string, string> context)
{
if (context == null || context.Count == 0)
return NoContext;

return new ReadOnlyDictionary<string, string>(new Dictionary<string, string>(context));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>4.4.1</Version>
<Version>4.5.0</Version>
<Authors>Codaxy</Authors>
<Company>Codaxy</Company>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/ConductorSharp.Patterns/ConductorSharp.Patterns.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<Authors>Codaxy</Authors>
<Company>Codaxy</Company>
<Version>4.4.1</Version>
<Version>4.5.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Nullable>disable</Nullable>
<PackAsTool>true</PackAsTool>
<ToolCommandName>dotnet-conductorsharp</ToolCommandName>
<Version>4.4.1</Version>
<Version>4.5.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading
Loading