w4c-workflows-api/Services/Execution/TaskRunMessage.cs

84 lines
2.9 KiB
C#
Raw Permalink Normal View History

using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using w4c_workflows.Models;
namespace w4c_workflows.Services.Execution;
/// <summary>
/// Serializes a <c>task.run</c> job from the compiled <see cref="WorkflowTask"/>
/// into the flat Redis Stream fields the worker understands (see
/// <see cref="TaskInvocation.FromFields"/>). This is the control-plane side of
/// the wire contract; the worker side deserializes the same field names.
/// </summary>
public static class TaskRunMessage
{
private static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.Web)
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};
/// <summary>
/// Builds the stream fields for executing <paramref name="task"/> as part of
/// <paramref name="run"/>. <paramref name="workingDir"/> is the directory
/// containing the task's code files; the entry file is taken from the task's
/// <c>EntryJson</c> and stays relative to it.
/// </summary>
public static IReadOnlyDictionary<string, string> ToFields(
WorkflowRun run,
WorkflowTask task,
string? input,
string? workingDir,
int attempt)
{
var entry = ParseEntry(task.EntryJson);
var fields = new Dictionary<string, string>
{
["type"] = TaskInvocation.TypeValue,
["run_id"] = run.Id.ToString(),
["task_id"] = task.Id.ToString(),
["task_key"] = task.Key,
["language"] = task.Language,
["entry_file"] = entry.File ?? string.Empty,
["tenant_id"] = run.TenantId,
["attempt"] = attempt.ToString(CultureInfo.InvariantCulture),
};
if (!string.IsNullOrWhiteSpace(entry.Function))
fields["entry_function"] = entry.Function;
var env = DeserializeEnv(task.EnvJson);
if (env.Count > 0)
fields["env"] = JsonSerializer.Serialize(env, Json);
if (input != null)
fields["input"] = input;
if (!string.IsNullOrWhiteSpace(workingDir))
fields["working_dir"] = workingDir;
if (!string.IsNullOrWhiteSpace(task.Server))
fields["server"] = task.Server!;
return fields;
}
private static EntryDefinition ParseEntry(string? entryJson)
{
if (!string.IsNullOrWhiteSpace(entryJson))
{
var entry = JsonSerializer.Deserialize<EntryDefinition>(entryJson, Json);
if (entry != null)
return entry;
}
return new EntryDefinition { File = string.Empty };
}
private static IReadOnlyDictionary<string, string> DeserializeEnv(string? envJson)
{
if (string.IsNullOrWhiteSpace(envJson))
return new Dictionary<string, string>();
return JsonSerializer.Deserialize<Dictionary<string, string>>(envJson, Json)
?? new Dictionary<string, string>();
}
}