Skip to content

Commit f5a163e

Browse files
committed
refactor(governance-runtime): extract execution orchestration helpers
1 parent 19a1446 commit f5a163e

3 files changed

Lines changed: 98 additions & 27 deletions

File tree

‎src/Governance/Runtime/Execution/Orchestration/GovernanceExecutionManager.cs‎

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,39 +46,35 @@ public async Task<GovernedExecutionResult<TState>> ExecuteApproved<TState>(
4646
ArgumentNullException.ThrowIfNull(resultingStateVersionProvider);
4747
ArgumentNullException.ThrowIfNull(governanceContext);
4848

49-
var resolution = await _resolutionManager.ResolveAndStore(
49+
var execution = await ResolveExecutionContext(
5050
requestId,
51+
mutation,
52+
currentState,
5153
currentStateVersion,
54+
resultingStateVersionProvider,
5255
governanceContext,
5356
strategy,
5457
cancellationToken).ConfigureAwait(false);
5558

56-
if (resolution.Outcome is MutationRequestVersionResolutionOutcome.RejectedAsStale or
59+
if (execution.Resolution.Outcome is MutationRequestVersionResolutionOutcome.RejectedAsStale or
5760
MutationRequestVersionResolutionOutcome.RequiresRenewedApproval)
5861
{
59-
return _outcomeHandler.BuildNonExecutedResult<TState>(resolution);
62+
return _outcomeHandler.BuildNonExecutedResult<TState>(execution.Resolution);
6063
}
6164

62-
var governedMutation = new GovernedMutation<TState>(mutation, requestId, resolution.Request.StateId);
6365
MutationResult<TState> mutationResult;
6466

6567
try
6668
{
67-
mutationResult = await _mutationEngine
68-
.ExecuteAsync(governedMutation, currentState, cancellationToken)
69-
.ConfigureAwait(false);
69+
mutationResult = await ExecuteMutation(execution, cancellationToken).ConfigureAwait(false);
7070
}
7171
catch (Exception ex)
7272
{
7373
await _outcomeHandler.PersistRejectedExecution(
74-
resolution.Request,
75-
governanceContext,
74+
execution.Resolution.Request,
75+
execution.GovernanceContext,
7676
$"Governed execution threw '{ex.GetType().Name}': {ex.Message}",
77-
new Dictionary<string, object>
78-
{
79-
["CurrentStateVersion"] = currentStateVersion,
80-
["ExecutionFailureType"] = ex.GetType().Name
81-
},
77+
GovernedExecutionFailureMetadataFactory.CreateExceptionMetadata(execution.CurrentStateVersion, ex),
8278
cancellationToken).ConfigureAwait(false);
8379

8480
throw;
@@ -87,35 +83,32 @@ await _outcomeHandler.PersistRejectedExecution(
8783
if (!mutationResult.IsSuccess || mutationResult.NewState is null)
8884
{
8985
var rejectedRequest = await _outcomeHandler.PersistRejectedExecution(
90-
resolution.Request,
91-
governanceContext,
86+
execution.Resolution.Request,
87+
execution.GovernanceContext,
9288
GovernedExecutionDecisionFactory.BuildRejectedExecutionReason(mutationResult),
93-
new Dictionary<string, object>
94-
{
95-
["CurrentStateVersion"] = currentStateVersion,
96-
["HasPolicyDecisions"] = mutationResult.PolicyDecisions.Count > 0,
97-
["HasValidationErrors"] = !mutationResult.ValidationResult.IsValid
98-
},
89+
GovernedExecutionFailureMetadataFactory.CreateRejectedExecutionMetadata(
90+
execution.CurrentStateVersion,
91+
mutationResult),
9992
cancellationToken).ConfigureAwait(false);
10093

10194
return _outcomeHandler.BuildNonExecutedResult(
102-
resolution with { Request = rejectedRequest },
95+
execution.Resolution with { Request = rejectedRequest },
10396
mutationResult);
10497
}
10598

106-
var resultingStateVersion = resultingStateVersionProvider(mutationResult.NewState);
99+
var resultingStateVersion = execution.ResultingStateVersionProvider(mutationResult.NewState);
107100
if (string.IsNullOrWhiteSpace(resultingStateVersion))
108101
throw new InvalidOperationException("Governed execution requires a non-empty resulting state version.");
109102

110103
var executedRequest = await _outcomeHandler.PersistExecutedRequest(
111-
resolution.Request,
104+
execution.Resolution.Request,
112105
resultingStateVersion,
113-
governanceContext,
106+
execution.GovernanceContext,
114107
mutationResult,
115108
cancellationToken).ConfigureAwait(false);
116109

117110
return _outcomeHandler.BuildExecutedResult(
118-
resolution,
111+
execution.Resolution,
119112
mutationResult,
120113
executedRequest,
121114
resultingStateVersion);
@@ -138,4 +131,38 @@ public Task<GovernedExecutionResult<TState>> ExecuteApproved<TState>(
138131
governanceContext,
139132
strategy,
140133
cancellationToken);
134+
135+
private async Task<GovernedExecutionContext<TState>> ResolveExecutionContext<TState>(
136+
string requestId,
137+
IMutation<TState> mutation,
138+
TState currentState,
139+
string currentStateVersion,
140+
Func<TState, string> resultingStateVersionProvider,
141+
MutationContext governanceContext,
142+
VersionedRequestResolutionStrategy strategy,
143+
CancellationToken cancellationToken)
144+
{
145+
var resolution = await _resolutionManager.ResolveAndStore(
146+
requestId,
147+
currentStateVersion,
148+
governanceContext,
149+
strategy,
150+
cancellationToken).ConfigureAwait(false);
151+
152+
return new GovernedExecutionContext<TState>(
153+
resolution,
154+
new GovernedMutation<TState>(mutation, resolution.Request),
155+
currentState,
156+
currentStateVersion,
157+
resultingStateVersionProvider,
158+
governanceContext);
159+
}
160+
161+
private Task<MutationResult<TState>> ExecuteMutation<TState>(
162+
GovernedExecutionContext<TState> execution,
163+
CancellationToken cancellationToken)
164+
=> _mutationEngine.ExecuteAsync(
165+
execution.Mutation,
166+
execution.CurrentState,
167+
cancellationToken);
141168
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using ModularityKit.Mutator.Abstractions.Context;
2+
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Model;
3+
using ModularityKit.Mutator.Governance.Runtime.Execution.Mutation;
4+
5+
namespace ModularityKit.Mutator.Governance.Runtime.Execution.Orchestration;
6+
7+
/// <summary>
8+
/// Carries the resolved runtime inputs for one governed execution attempt.
9+
/// </summary>
10+
internal sealed record GovernedExecutionContext<TState>(
11+
MutationRequestVersionResolution Resolution,
12+
GovernedMutation<TState> Mutation,
13+
TState CurrentState,
14+
string CurrentStateVersion,
15+
Func<TState, string> ResultingStateVersionProvider,
16+
MutationContext GovernanceContext);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using ModularityKit.Mutator.Abstractions.Results;
2+
3+
namespace ModularityKit.Mutator.Governance.Runtime.Execution.Orchestration;
4+
5+
/// <summary>
6+
/// Builds consistent governance metadata payloads for execution failures.
7+
/// </summary>
8+
internal static class GovernedExecutionFailureMetadataFactory
9+
{
10+
public static IReadOnlyDictionary<string, object> CreateExceptionMetadata(
11+
string currentStateVersion,
12+
Exception exception)
13+
=> new Dictionary<string, object>
14+
{
15+
["CurrentStateVersion"] = currentStateVersion,
16+
["ExecutionFailureType"] = exception.GetType().Name
17+
};
18+
19+
public static IReadOnlyDictionary<string, object> CreateRejectedExecutionMetadata<TState>(
20+
string currentStateVersion,
21+
MutationResult<TState> mutationResult)
22+
=> new Dictionary<string, object>
23+
{
24+
["CurrentStateVersion"] = currentStateVersion,
25+
["HasPolicyDecisions"] = mutationResult.PolicyDecisions.Count > 0,
26+
["HasValidationErrors"] = !mutationResult.ValidationResult.IsValid
27+
};
28+
}

0 commit comments

Comments
 (0)