namespace AcDream.App.Rendering; internal readonly record struct ResourceShutdownOperation(string Name, Action Execute); internal sealed record ResourceShutdownStage( string Name, ResourceShutdownOperation[] Operations); /// /// Owns application-level shutdown ordering. Operations within one stage are /// independent and are all attempted; later stages remain protected until the /// current stage has converged. Successful operations are never replayed. /// internal sealed class ResourceShutdownTransaction(params ResourceShutdownStage[] stages) { private sealed class StageState(int operationCount) { public bool[] Complete { get; } = new bool[operationCount]; } private const int MaximumConsecutiveStalledPasses = 2; private readonly ResourceShutdownStage[] _stages = stages ?? throw new ArgumentNullException(nameof(stages)); private readonly StageState[] _states = stages.Select(stage => new StageState(stage.Operations.Length)).ToArray(); private int _currentStage; private bool _completing; public bool IsComplete => _currentStage == _stages.Length; internal int CurrentStage => _currentStage; public void CompleteOrThrow() { if (_completing || IsComplete) return; _completing = true; try { int stalledPasses = 0; List? latestFailures = null; while (!IsComplete) { bool progressed = AdvanceCurrentStage(out List? failures); latestFailures = failures; if (progressed) { stalledPasses = 0; continue; } stalledPasses++; if (stalledPasses < MaximumConsecutiveStalledPasses) continue; ResourceShutdownStage stage = _stages[_currentStage]; throw new AggregateException( $"Shutdown stage '{stage.Name}' did not converge after retrying its pending operations.", latestFailures ?? [new InvalidOperationException("The shutdown stage made no progress and reported no failure.")]); } } finally { _completing = false; } } private bool AdvanceCurrentStage(out List? failures) { ResourceShutdownStage stage = _stages[_currentStage]; StageState state = _states[_currentStage]; bool progressed = false; failures = null; for (int i = 0; i < stage.Operations.Length; i++) { if (state.Complete[i]) continue; ResourceShutdownOperation operation = stage.Operations[i]; try { operation.Execute(); state.Complete[i] = true; progressed = true; } catch (Exception error) { (failures ??= []).Add(new InvalidOperationException( $"Shutdown operation '{operation.Name}' failed in stage '{stage.Name}'.", error)); } } if (state.Complete.All(static complete => complete)) { _currentStage++; progressed = true; } return progressed; } }