HedgingExecutionContext<T>
The context associated with an execution of hedging resilience strategy.
It holds the resources for all executed hedged tasks (primary + secondary) and is responsible for resource disposal.
using Polly.Hedging.Controller;
using Polly.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Polly.Hedging.Utils
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
internal sealed class HedgingExecutionContext<[System.Runtime.CompilerServices.Nullable(2)] T> : IAsyncDisposable
{
[System.Runtime.CompilerServices.NullableContext(0)]
public readonly struct ExecutionInfo<[System.Runtime.CompilerServices.Nullable(2)] TResult> : IEquatable<ExecutionInfo<TResult>>
{
[System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
[field: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
public TaskExecution<T> Execution {
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
get;
[param: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
set;
}
public bool Loaded { get; set; }
[System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
[field: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Outcome<TResult>? Outcome {
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
get;
[param: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
set;
}
public ExecutionInfo([System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})] TaskExecution<T> Execution, bool Loaded, [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] Outcome<TResult>? Outcome)
{
Execution = Execution;
Loaded = Loaded;
Outcome = Outcome;
}
[CompilerGenerated]
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("ExecutionInfo");
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
stringBuilder.Append(' ');
stringBuilder.Append('}');
return stringBuilder.ToString();
}
[CompilerGenerated]
private bool PrintMembers(StringBuilder builder)
{
builder.Append("Execution = ");
builder.Append(Execution);
builder.Append(", Loaded = ");
builder.Append(Loaded.ToString());
builder.Append(", Outcome = ");
builder.Append(Outcome.ToString());
return true;
}
public static bool operator !=(ExecutionInfo<TResult> left, ExecutionInfo<TResult> right)
{
return !(left == right);
}
public static bool operator ==(ExecutionInfo<TResult> left, ExecutionInfo<TResult> right)
{
return left.Equals(right);
}
[CompilerGenerated]
public override int GetHashCode()
{
return (EqualityComparer<TaskExecution<T>>.Default.GetHashCode(Execution) * -1521134295 + EqualityComparer<bool>.Default.GetHashCode(Loaded)) * -1521134295 + EqualityComparer<Outcome<TResult>?>.Default.GetHashCode(Outcome);
}
[CompilerGenerated]
public override bool Equals(object obj)
{
if (obj is ExecutionInfo<TResult>)
return Equals((ExecutionInfo<TResult>)obj);
return false;
}
[CompilerGenerated]
public bool Equals(ExecutionInfo<TResult> other)
{
if (EqualityComparer<TaskExecution<T>>.Default.Equals(Execution, other.Execution) && EqualityComparer<bool>.Default.Equals(Loaded, other.Loaded))
return EqualityComparer<Outcome<TResult>?>.Default.Equals(Outcome, other.Outcome);
return false;
}
[CompilerGenerated]
public void Deconstruct([System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})] out TaskExecution<T> Execution, out bool Loaded, [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] out Outcome<TResult>? Outcome)
{
Execution = this.Execution;
Loaded = this.Loaded;
Outcome = this.Outcome;
}
}
private readonly List<TaskExecution<T>> _tasks = new List<TaskExecution<T>>();
private readonly List<TaskExecution<T>> _executingTasks = new List<TaskExecution<T>>();
private readonly ObjectPool<TaskExecution<T>> _executionPool;
private readonly TimeProvider _timeProvider;
private readonly int _maxAttempts;
private readonly Action<HedgingExecutionContext<T>> _onReset;
public int LoadedTasks => _tasks.Count;
[System.Runtime.CompilerServices.Nullable(2)]
[field: System.Runtime.CompilerServices.Nullable(2)]
public ResilienceContext PrimaryContext {
[System.Runtime.CompilerServices.NullableContext(2)]
get;
[System.Runtime.CompilerServices.NullableContext(2)]
private set;
}
public bool IsInitialized => PrimaryContext != null;
public IReadOnlyList<TaskExecution<T>> Tasks => _tasks;
private bool ContinueOnCapturedContext => PrimaryContext.ContinueOnCapturedContext;
public HedgingExecutionContext(ObjectPool<TaskExecution<T>> executionPool, TimeProvider timeProvider, int maxAttempts, Action<HedgingExecutionContext<T>> onReset)
{
_executionPool = executionPool;
_timeProvider = timeProvider;
_maxAttempts = maxAttempts;
_onReset = onReset;
}
internal void Initialize(ResilienceContext context)
{
PrimaryContext = context;
}
[AsyncStateMachine(typeof(<LoadExecutionAsync>d__21<>))]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
0,
0,
1
})]
public ValueTask<ExecutionInfo<T>> LoadExecutionAsync<[System.Runtime.CompilerServices.Nullable(2)] TState>([System.Runtime.CompilerServices.Nullable(new byte[] {
1,
1,
1,
0,
0,
1
})] Func<ResilienceContext, TState, ValueTask<Outcome<T>>> primaryCallback, TState state)
{
<LoadExecutionAsync>d__21<TState> stateMachine = default(<LoadExecutionAsync>d__21<TState>);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder<ExecutionInfo<T>>.Create();
stateMachine.<>4__this = this;
stateMachine.primaryCallback = primaryCallback;
stateMachine.state = state;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[AsyncStateMachine(typeof(HedgingExecutionContext<>.<DisposeAsync>d__22))]
public ValueTask DisposeAsync()
{
<DisposeAsync>d__22 stateMachine = default(<DisposeAsync>d__22);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder.Create();
stateMachine.<>4__this = this;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start<<DisposeAsync>d__22>(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[AsyncStateMachine(typeof(HedgingExecutionContext<>.<TryWaitForCompletedExecutionAsync>d__23))]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
2,
1
})]
public ValueTask<TaskExecution<T>> TryWaitForCompletedExecutionAsync(TimeSpan hedgingDelay)
{
<TryWaitForCompletedExecutionAsync>d__23 stateMachine = default(<TryWaitForCompletedExecutionAsync>d__23);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder<TaskExecution<T>>.Create();
stateMachine.<>4__this = this;
stateMachine.hedgingDelay = hedgingDelay;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
0,
1
})]
private ExecutionInfo<T> CreateExecutionInfoWhenNoExecution()
{
if (_executingTasks.Count == 0) {
TaskExecution<T> taskExecution = Enumerable.First<TaskExecution<T>>((IEnumerable<TaskExecution<T>>)_tasks, (Func<TaskExecution<T>, bool>)((TaskExecution<T> t) => t.ExecutionTaskSafe.IsCompleted));
taskExecution.AcceptOutcome();
return new ExecutionInfo<T>(null, false, taskExecution.Outcome);
}
return new ExecutionInfo<T>(null, false, null);
}
private Task<Task> WaitForTaskCompetitionAsync()
{
switch (_executingTasks.Count) {
case 1:
return <WaitForTaskCompetitionAsync>g__AwaitTask|25_0(_executingTasks[0], ContinueOnCapturedContext);
case 2:
return Task.WhenAny(new Task[2] {
_executingTasks[0].ExecutionTaskSafe,
_executingTasks[1].ExecutionTaskSafe
});
default:
return Task.WhenAny(Enumerable.Select<TaskExecution<T>, Task>((IEnumerable<TaskExecution<T>>)_executingTasks, (Func<TaskExecution<T>, Task>)((TaskExecution<T> v) => v.ExecutionTaskSafe)));
}
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
private TaskExecution<T> TryRemoveExecutedTask()
{
TaskExecution<T> taskExecution = _executingTasks.Find((TaskExecution<T> v) => v.ExecutionTaskSafe.IsCompleted);
if (taskExecution != null) {
_executingTasks.Remove(taskExecution);
return taskExecution;
}
return null;
}
private void UpdateOriginalContext()
{
if (LoadedTasks != 0) {
TaskExecution<T> taskExecution = Enumerable.FirstOrDefault<TaskExecution<T>>((IEnumerable<TaskExecution<T>>)Tasks, (Func<TaskExecution<T>, bool>)((TaskExecution<T> t) => t.IsAccepted));
if (taskExecution != null)
PrimaryContext.Properties.AddOrReplaceProperties(taskExecution.Context.Properties);
}
}
private void Reset()
{
_tasks.Clear();
_executingTasks.Clear();
PrimaryContext = null;
_onReset(this);
}
}
}