namespace s8n_runtime; public abstract class WorkflowRuntime { private RuntimeStatus status; public RuntimeStateStoreStrategy StoreState { get; set; } = RuntimeStateStoreStrategy.WhenExit; protected IServiceProvider? serviceProvider; public DateTime Timestamp => DateTime.Now; public RuntimeStatus Status { get => status; set { status = value; WorkflowEditApiChannel.LogServerChannel?.Writer.TryWrite(new(string.Empty, "Workflow.Status", value)); } } public Dictionary Settings { get; private set; } = []; public IEnumerable AllNodes() { foreach (var f in EnumFields()) { var value = f.GetValue(this); if (value is IWorkflowRuntimeNode node) yield return node; } } private IEnumerable EnumFields() { return GetType() .GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) .Where(f => f.DeclaringType == GetType()); } public virtual void Prepare() { foreach (var f in EnumFields()) { var value = f.GetValue(this); if (value is null) { f.SetValue(this, serviceProvider?.GetService(f.FieldType) ?? Activator.CreateInstance(f.FieldType)); } } } public async virtual Task RunAsync(CancellationToken cancellation) { foreach (var node in AllNodes()) { cancellation.ThrowIfCancellationRequested(); if (node is IWorkflowNodeRunnable runnable) await runnable.OnStart(this, cancellation); if (node.Status == RuntimeStatus.NotReady) { node.Status = RuntimeStatus.Started; } } Status = RuntimeStatus.Started; } public virtual async Task OnStop() { foreach (var node in AllNodes()) { // When already stopped or skipped on start if (node.Status == RuntimeStatus.Skipped || node.Status == RuntimeStatus.Stopped) continue; if (node is IWorkflowNodeRunnable runnable) await runnable.OnStop(); } foreach (var node in AllNodes().OfType()) { node.Dispose(); } Status = RuntimeStatus.Stopped; } public override string ToString() { return $"Status: {Status}, Count: {AllNodes().Count()}"; } }