Skip to content

Commit

Permalink
feat: index based Schedule.cs access
Browse files Browse the repository at this point in the history
  • Loading branch information
bmazzarol committed Oct 29, 2023
1 parent 8a5b135 commit 1d04d89
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 11 deletions.
15 changes: 4 additions & 11 deletions Eon.Tests/Examples/PollyExamples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,15 @@ public static async Task Case1()
{
#region Example1

// build any schedule using Eon
// build a schedule using Eon
Schedule schedule = Schedule.Linear(1).Take(5);
// get the durations
var durations = schedule.ToArray();
// now create the options
RetryStrategyOptions options = new RetryStrategyOptions
{
MaxRetryAttempts = schedule.Count ?? int.MaxValue,
Delay = TimeSpan.Zero,
DelayGenerator = x =>
ValueTask.FromResult<TimeSpan?>((TimeSpan)durations[x.AttemptNumber])
ValueTask.FromResult<TimeSpan?>((TimeSpan)schedule[x.AttemptNumber])
};
ResiliencePipeline pipeline = new ResiliencePipelineBuilder().AddRetry(options).Build();
int attempts = 0;
Expand All @@ -43,20 +41,15 @@ public static async Task Case2()
{
#region Example2

// build any schedule using Eon
// build a schedule using Eon
Schedule schedule = Schedule.Linear(1);
// now create the options
RetryStrategyOptions options = new RetryStrategyOptions
{
MaxRetryAttempts = int.MaxValue,
Delay = TimeSpan.Zero,
DelayGenerator = x =>
{
var enumerator = x.AttemptNumber == 0 ? schedule.GetEnumerator() : null;
return ValueTask.FromResult<TimeSpan?>(
enumerator?.MoveNext() == true ? (TimeSpan)enumerator.Current : null
);
}
ValueTask.FromResult<TimeSpan?>((TimeSpan)schedule[x.AttemptNumber])
};
ResiliencePipeline pipeline = new ResiliencePipelineBuilder().AddRetry(options).Build();
int attempts = 0;
Expand Down
14 changes: 14 additions & 0 deletions Eon.Tests/ScheduleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,18 @@ public static void Case2()
var schedule = Schedule.Forever;
((IEnumerable)schedule).GetEnumerator().MoveNext().Should().BeTrue();
}

[Fact(DisplayName = "Schedule can be accessed by index")]
public static void Case3()
{
var schedule = Schedule.Linear(100);
schedule[0].Should().Be(100);
schedule[2].Should().Be(300);
schedule[3].Should().Be(400);
schedule[4].Should().Be(500);
schedule[5].Should().Be(600);
schedule[5].Should().Be(600);
schedule[100].Should().Be(10100);
schedule[1].Should().Be(200);
}
}
60 changes: 60 additions & 0 deletions Eon/Schedule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,64 @@ IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

private readonly object _lock = new();
private int _position;
private Duration[] _buffer = Array.Empty<Duration>();
private IEnumerator<Duration>? _enumerator;

/// <summary>
/// Provides `index` based access to a shared enumerated version of `this` <see cref="Schedule"/>.
/// This will grow the internal buffer in a synchronized way by doubling the current
/// length of the buffer when it is filled.
/// </summary>
/// <remarks>This can only ever be as large as <see cref="int.MaxValue"/></remarks>
/// <remarks>This can be used to integrate <see cref="Schedule"/> into places that
/// take delegate based back-off algorithms</remarks>
/// <param name="index">index</param>
/// <exception cref="IndexOutOfRangeException">when the <see cref="Schedule"/> has
/// less emissions than the provided `index`</exception>
public Duration this[int index]
{
get
{
lock (_lock)
{
TryFillBuffer(index);
return _buffer[index];
}
}
}

private void TryFillBuffer(int index)
{
_enumerator ??= GetEnumerator();

var currentLength = _position;
if (currentLength != 0 && currentLength > index)
{
return;
}

var size = currentLength == 0 ? 4 : currentLength * 2;

if (size <= index)
{
size = index + 1;
}

var newBuffer = new Duration[size];

if (_buffer.Length != 0)
{
Array.Copy(_buffer, 0, newBuffer, 0, _buffer.Length);
}

for (; _position < size && _enumerator.MoveNext(); _position++)
{
newBuffer[_position] = _enumerator.Current;
}

_buffer = newBuffer;
}
}

0 comments on commit 1d04d89

Please sign in to comment.