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

48 lines
1.9 KiB
C#

using System.Globalization;
namespace w4c_workflows.Services.Execution;
/// <summary>
/// A <c>task.result</c> event as consumed by the run lifecycle engine. The
/// worker publishes these via <see cref="TaskResultMessage.ToFields"/>; this
/// record is the control-plane parse of the same flat field names.
/// </summary>
public sealed record TaskResult(
string RunId,
string TaskId,
int Attempt,
string TenantId,
bool Success,
int ExitCode,
string? Output,
string? Error,
long DurationMs)
{
/// <summary>Parses a stream message into a result, throwing if a required field is missing.</summary>
public static TaskResult FromFields(IReadOnlyDictionary<string, string> fields)
{
static string Get(IReadOnlyDictionary<string, string> fields, string key) =>
fields.TryGetValue(key, out var value) && !string.IsNullOrEmpty(value)
? value
: throw new InvalidOperationException($"missing required result field '{key}'");
static int GetInt(IReadOnlyDictionary<string, string> fields, string key, int fallback) =>
fields.TryGetValue(key, out var raw) && int.TryParse(raw, out var n) ? n : fallback;
static long GetLong(IReadOnlyDictionary<string, string> fields, string key, long fallback) =>
fields.TryGetValue(key, out var raw) && long.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out var n) ? n : fallback;
var status = Get(fields, "status");
return new TaskResult(
Get(fields, "run_id"),
Get(fields, "task_id"),
GetInt(fields, "attempt", 1),
Get(fields, "tenant_id"),
string.Equals(status, "succeeded", StringComparison.Ordinal),
GetInt(fields, "exit_code", -1),
fields.GetValueOrDefault("output"),
fields.GetValueOrDefault("error"),
GetLong(fields, "duration_ms", 0));
}
}