w4c-workflows-api/Models/WorkflowYaml.cs
2026-09-12 01:02:46 +03:00

140 lines
5.9 KiB
C#

namespace w4c_workflows.Models;
// ---------------------------------------------------------------------------
// YAML shape (authoritative source of truth, stored in git under workflows/).
// Field names are camelCase in YAML; YamlDotNet maps them via CamelCaseNaming.
// ---------------------------------------------------------------------------
public class WorkflowDefinition
{
public string? Name { get; set; }
public string? Description { get; set; }
public string? Version { get; set; } // user-facing build/version, e.g. "1.0.1"
public string? Mode { get; set; } // function | durable | handler
public string? Language { get; set; } // shell | javascript | typescript | csharp | python
public string? Target { get; set; } // execution host (default: "default")
/// <summary>Managed-server id (or alias) that task code should run on. A task-level
/// <c>server</c> overrides this header default; when set, the worker executes the task
/// on that server via SSH instead of a local subprocess.</summary>
public string? Server { get; set; }
public TriggerDefinition? Trigger { get; set; }
public EntryDefinition? Entry { get; set; }
public Dictionary<string, string>? Env { get; set; }
public List<TaskDefinition>? Tasks { get; set; }
/// <summary>
/// Workflow-level connections between node tasks. Task-local <c>edges</c> take
/// precedence for their own <c>from</c>; when both are present they are merged.
/// <c>next</c>/<c>onError</c> stay valid sugar (main[0] and the error port).
/// </summary>
public List<TaskEdgeDefinition>? Edges { get; set; }
}
/// <summary>
/// One step of a workflow. A step is either a script task (legacy: <c>language</c>
/// + <c>entry</c>) or a node task (<see cref="Node"/> + <see cref="Parameters"/>).
/// The two modes are mutually exclusive.
/// </summary>
public class TaskDefinition
{
public string? Id { get; set; }
public string? Parent { get; set; } // "root" | another task id (organizational)
public string? Next { get; set; } // success flow → lowers to main[0]
public string? OnError { get; set; } // failure flow (compensation) → lowers to the error port
public string? Language { get; set; } // inherits workflow language when omitted
public string? Mode { get; set; } // inherits workflow mode when omitted
/// <summary>Target managed server for this task. Overrides the workflow header <c>server</c>.</summary>
public string? Server { get; set; }
public EntryDefinition? Entry { get; set; }
public Dictionary<string, string>? Env { get; set; }
// ---- node-mode fields (n8n-style integration steps) --------------------
/// <summary>Catalog blueprint this step runs. Requires <see cref="Parameters"/>.</summary>
public NodeTaskDefinition? Node { get; set; }
/// <summary>
/// Node parameters. Values may be literals or expressions (see the parameter
/// interpolation rules); nested mappings/sequences are supported.
/// </summary>
public Dictionary<string, object?>? Parameters { get; set; }
/// <summary>
/// Credentials this node needs, keyed by the blueprint's credential alias;
/// the value is the vault credential id or its unique name. Resolved to
/// decrypted data at run time.
/// </summary>
public Dictionary<string, string>? Credentials { get; set; }
/// <summary>Explicit outgoing connections owned by this step (from = this id).</summary>
public List<TaskEdgeDefinition>? Edges { get; set; }
/// <summary>Per-node retry policy.</summary>
public TaskRetryDefinition? Retry { get; set; }
/// <summary>Route failures to the error port instead of failing the run.</summary>
public bool? ContinueOnFail { get; set; }
/// <summary>Overrides the blueprint run mode: <c>eachItem</c> | <c>allItems</c>.</summary>
public string? RunMode { get; set; }
}
/// <summary>Reference to a node type in the catalog, with an optional pinned version.</summary>
public class NodeTaskDefinition
{
public string? Type { get; set; }
/// <summary>Pinned blueprint version; null/absent means "use the default (highest)".</summary>
public double? Version { get; set; }
}
/// <summary>
/// A directed connection between two steps. <see cref="From"/> defaults to the
/// owning task for task-local edges; a global edge must set it.
/// </summary>
public class TaskEdgeDefinition
{
/// <summary>Source task id (defaults to the owning task).</summary>
public string? From { get; set; }
/// <summary>Source output port index; defaults to 0 (main).</summary>
public int? Output { get; set; }
/// <summary>Target task id.</summary>
public string? To { get; set; }
/// <summary>Target input port index; defaults to 0 (main).</summary>
public int? Input { get; set; }
}
/// <summary>Retry policy for a node task.</summary>
public class TaskRetryDefinition
{
/// <summary>Total attempts (1 = no retry).</summary>
public int? MaxTries { get; set; }
/// <summary>Initial delay between attempts, e.g. "2s" or "500ms".</summary>
public string? WaitBetweenTries { get; set; }
/// <summary>Multiplier applied to the delay after each failed attempt.</summary>
public double? BackoffFactor { get; set; }
/// <summary>HTTP status codes that are retried before the policy gives up.</summary>
public List<int>? RetryOnStatus { get; set; }
}
public class TriggerDefinition
{
public string? Type { get; set; } // queue | cron | interval | webhook | event
public string? Stream { get; set; } // queue: stream/topic (default wf:{tenant}:events)
public string? Cron { get; set; } // cron: "0 */6 * * *"
public string? Interval { get; set; } // interval: "30m", "2h", "45s"
public string? WebhookPath { get; set; } // webhook: "/h/orders"
}
public class EntryDefinition
{
public string? File { get; set; }
public string? Function { get; set; }
}