|
| 1 | +using Microsoft.Extensions.DependencyInjection; |
| 2 | +using ModularityKit.Mutator.Abstractions; |
| 3 | +using ModularityKit.Mutator.Abstractions.Changes; |
| 4 | +using ModularityKit.Mutator.Abstractions.Context; |
| 5 | +using ModularityKit.Mutator.Abstractions.Engine; |
| 6 | +using ModularityKit.Mutator.Abstractions.Intent; |
| 7 | +using ModularityKit.Mutator.Abstractions.Results; |
| 8 | +using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory; |
| 9 | +using ModularityKit.Mutator.Governance.Abstractions.Requests.Model; |
| 10 | +using ModularityKit.Mutator.Governance.Abstractions.Resolution.Strategies; |
| 11 | +using ModularityKit.Mutator.Governance.Runtime.Execution.Orchestration; |
| 12 | +using ModularityKit.Mutator.Governance.Runtime.Resolution.Execution; |
| 13 | +using ModularityKit.Mutator.Governance.Runtime.Storage; |
| 14 | +using ModularityKit.Mutator.Runtime; |
| 15 | + |
| 16 | +namespace GovernedExecution.Scenarios; |
| 17 | + |
| 18 | +internal static class GovernanceExecutionScenario |
| 19 | +{ |
| 20 | + public static async Task Run() |
| 21 | + { |
| 22 | + var services = new ServiceCollection(); |
| 23 | + services.AddMutators(MutationEngineOptions.Strict); |
| 24 | + await using var provider = services.BuildServiceProvider(); |
| 25 | + |
| 26 | + var engine = provider.GetRequiredService<IMutationEngine>(); |
| 27 | + var store = new InMemoryMutationRequestStore(); |
| 28 | + var resolutionManager = new MutationRequestVersionResolutionManager(store, new MutationRequestVersionResolver()); |
| 29 | + var executionManager = new GovernanceExecutionManager(store, resolutionManager, engine); |
| 30 | + |
| 31 | + var request = await store.Create(MutationRequestFactory.Approved( |
| 32 | + stateId: "tenant-42:feature-flags", |
| 33 | + stateType: "FeatureFlagState", |
| 34 | + mutationType: nameof(EnableFeatureMutation), |
| 35 | + intent: new MutationIntent |
| 36 | + { |
| 37 | + OperationName = "EnableFeature", |
| 38 | + Category = "Configuration", |
| 39 | + Description = "Enable a rollout after governance approval" |
| 40 | + }, |
| 41 | + context: MutationContext.User("requester-1", "Requester One", "Enable guarded rollout"), |
| 42 | + expectedStateVersion: "v10")); |
| 43 | + |
| 44 | + var currentState = new FeatureFlagState( |
| 45 | + request.StateId, |
| 46 | + IsEnabled: false, |
| 47 | + Version: "v10"); |
| 48 | + |
| 49 | + var execution = await executionManager.ExecuteApproved( |
| 50 | + request.RequestId, |
| 51 | + new EnableFeatureMutation(MutationContext.Service("release-orchestrator", "Execute approved rollout"), "v11"), |
| 52 | + currentState, |
| 53 | + currentState.Version, |
| 54 | + resultingStateVersionProvider: state => state.Version, |
| 55 | + governanceContext: MutationContext.Service("governance-runtime", "Execute approved governance request"), |
| 56 | + strategy: VersionedRequestResolutionStrategy.RejectStale); |
| 57 | + |
| 58 | + Console.WriteLine("=== Governed Execution ==="); |
| 59 | + Console.WriteLine($"Executed: {execution.WasExecuted}"); |
| 60 | + Console.WriteLine($"Resolution: {execution.Resolution.Outcome}"); |
| 61 | + Console.WriteLine($"Request status: {execution.Request.Status}"); |
| 62 | + Console.WriteLine($"Resulting version: {execution.ResultingStateVersion ?? "-"}"); |
| 63 | + Console.WriteLine($"Last decision: {execution.Request.Decisions[^1].Type}"); |
| 64 | + Console.WriteLine($"Reason: {execution.Request.Decisions[^1].Reason}"); |
| 65 | + } |
| 66 | + |
| 67 | + private sealed record FeatureFlagState(string StateId, bool IsEnabled, string Version); |
| 68 | + |
| 69 | + private sealed class EnableFeatureMutation(MutationContext context, string nextVersion) : IMutation<FeatureFlagState> |
| 70 | + { |
| 71 | + public MutationIntent Intent { get; } = new() |
| 72 | + { |
| 73 | + OperationName = "EnableFeature", |
| 74 | + Category = "Configuration", |
| 75 | + Description = "Enable a feature after governance approval" |
| 76 | + }; |
| 77 | + |
| 78 | + public MutationContext Context { get; } = context; |
| 79 | + |
| 80 | + public MutationResult<FeatureFlagState> Apply(FeatureFlagState state) |
| 81 | + { |
| 82 | + var newState = state with |
| 83 | + { |
| 84 | + IsEnabled = true, |
| 85 | + Version = nextVersion |
| 86 | + }; |
| 87 | + |
| 88 | + return MutationResult<FeatureFlagState>.Success( |
| 89 | + newState, |
| 90 | + ChangeSet.Single(StateChange.Modified("IsEnabled", state.IsEnabled, newState.IsEnabled))); |
| 91 | + } |
| 92 | + |
| 93 | + public ValidationResult Validate(FeatureFlagState state) |
| 94 | + { |
| 95 | + return state.IsEnabled |
| 96 | + ? ValidationResult.WithError("IsEnabled", "Feature is already enabled.") |
| 97 | + : ValidationResult.Success(); |
| 98 | + } |
| 99 | + |
| 100 | + public MutationResult<FeatureFlagState> Simulate(FeatureFlagState state) => Apply(state); |
| 101 | + } |
| 102 | +} |
0 commit comments