namespace Zcbot.WindowsNode; internal enum JobTransitionMode { Normal, Recovery, } internal static class JobStateMachine { internal const string Accepted = "accepted"; internal const string DownloadingInputs = "downloading_inputs"; internal const string ReadyToRun = "ready_to_run"; internal const string SoftwareRunning = "software_running"; internal const string UploadingOutputs = "uploading_outputs"; internal const string Succeeded = "succeeded"; internal const string Failed = "failed"; internal const string Cancelled = "cancelled"; private static readonly IReadOnlyDictionary> Transitions = new Dictionary>(StringComparer.Ordinal) { [Accepted] = Set(DownloadingInputs, Failed, Cancelled), [DownloadingInputs] = Set(DownloadingInputs, ReadyToRun, Failed, Cancelled), [ReadyToRun] = Set(SoftwareRunning, Failed, Cancelled), [SoftwareRunning] = Set(UploadingOutputs, Failed, Cancelled), [UploadingOutputs] = Set(UploadingOutputs, Succeeded, Failed, Cancelled), [Succeeded] = Set(), [Failed] = Set(), [Cancelled] = Set(), }; internal static IReadOnlySet Stages { get; } = Transitions.Keys.ToHashSet(StringComparer.Ordinal); internal static IReadOnlySet TerminalStages { get; } = Set(Succeeded, Failed, Cancelled); internal static bool IsTerminal(string stage) => TerminalStages.Contains(stage); internal static void EnsureTransition( string current, string next, JobTransitionMode mode = JobTransitionMode.Normal) { if (!Transitions.ContainsKey(current) || !Transitions.ContainsKey(next)) { throw new InvalidDataException("Unsupported local job stage."); } if (current == next && !IsTerminal(current)) { return; } if (Transitions[current].Contains(next)) { return; } if (mode == JobTransitionMode.Recovery && !IsTerminal(current) && next is DownloadingInputs or UploadingOutputs) { return; } throw new InvalidDataException($"Invalid local job transition: {current} -> {next}."); } internal static void EnsureTerminalStatus(string status) { if (!TerminalStages.Contains(status)) { throw new InvalidDataException("Unsupported local terminal status."); } } private static IReadOnlySet Set(params string[] values) => values.ToHashSet(StringComparer.Ordinal); }