zcbot/windows-node/Zcbot.WindowsNode/Jobs/JobStateMachine.cs

78 lines
2.7 KiB
C#

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<string, IReadOnlySet<string>> Transitions =
new Dictionary<string, IReadOnlySet<string>>(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<string> Stages { get; } =
Transitions.Keys.ToHashSet(StringComparer.Ordinal);
internal static IReadOnlySet<string> 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<string> Set(params string[] values) =>
values.ToHashSet(StringComparer.Ordinal);
}