2021-11-27 02:10:56 +00:00
|
|
|
namespace Myriad.Gateway.State;
|
2021-04-29 09:10:19 +00:00
|
|
|
|
2021-11-27 02:10:56 +00:00
|
|
|
public class HeartbeatWorker: IAsyncDisposable
|
2021-04-29 09:10:19 +00:00
|
|
|
{
|
2021-11-27 02:10:56 +00:00
|
|
|
private Task? _worker;
|
|
|
|
private CancellationTokenSource? _workerCts;
|
|
|
|
|
|
|
|
public TimeSpan? CurrentHeartbeatInterval { get; private set; }
|
|
|
|
|
|
|
|
public async ValueTask DisposeAsync()
|
2021-04-29 09:10:19 +00:00
|
|
|
{
|
2021-11-27 02:10:56 +00:00
|
|
|
await Stop();
|
|
|
|
}
|
2021-08-27 15:03:47 +00:00
|
|
|
|
2021-11-27 02:10:56 +00:00
|
|
|
public async ValueTask Start(TimeSpan heartbeatInterval, Func<Task> callback)
|
|
|
|
{
|
|
|
|
if (_worker != null)
|
|
|
|
await Stop();
|
2021-04-29 09:10:19 +00:00
|
|
|
|
2021-11-27 02:10:56 +00:00
|
|
|
CurrentHeartbeatInterval = heartbeatInterval;
|
|
|
|
_workerCts = new CancellationTokenSource();
|
|
|
|
_worker = Worker(heartbeatInterval, callback, _workerCts.Token);
|
|
|
|
}
|
2021-04-29 09:10:19 +00:00
|
|
|
|
2021-11-27 02:10:56 +00:00
|
|
|
public async ValueTask Stop()
|
|
|
|
{
|
|
|
|
if (_worker == null)
|
|
|
|
return;
|
2021-04-29 09:10:19 +00:00
|
|
|
|
2021-11-27 02:10:56 +00:00
|
|
|
_workerCts?.Cancel();
|
|
|
|
try
|
2021-04-29 09:10:19 +00:00
|
|
|
{
|
2021-11-27 02:10:56 +00:00
|
|
|
await _worker;
|
2021-04-29 09:10:19 +00:00
|
|
|
}
|
2021-11-27 02:10:56 +00:00
|
|
|
catch (TaskCanceledException) { }
|
2021-08-27 15:03:47 +00:00
|
|
|
|
2021-11-27 02:10:56 +00:00
|
|
|
_worker?.Dispose();
|
|
|
|
_workerCts?.Dispose();
|
|
|
|
_worker = null;
|
|
|
|
CurrentHeartbeatInterval = null;
|
|
|
|
}
|
2021-04-29 09:10:19 +00:00
|
|
|
|
2021-11-27 02:10:56 +00:00
|
|
|
private async Task Worker(TimeSpan heartbeatInterval, Func<Task> callback, CancellationToken ct)
|
|
|
|
{
|
|
|
|
var initialDelay = GetInitialHeartbeatDelay(heartbeatInterval);
|
|
|
|
await Task.Delay(initialDelay, ct);
|
2021-04-29 09:10:19 +00:00
|
|
|
|
2021-11-27 02:10:56 +00:00
|
|
|
while (!ct.IsCancellationRequested)
|
2021-04-29 09:10:19 +00:00
|
|
|
{
|
2021-11-27 02:10:56 +00:00
|
|
|
await callback();
|
|
|
|
await Task.Delay(heartbeatInterval, ct);
|
2021-04-29 09:10:19 +00:00
|
|
|
}
|
|
|
|
}
|
2021-11-27 02:10:56 +00:00
|
|
|
|
|
|
|
private static TimeSpan GetInitialHeartbeatDelay(TimeSpan heartbeatInterval) =>
|
|
|
|
// Docs specify `heartbeat_interval * random.random()` but we'll add a lil buffer :)
|
|
|
|
heartbeatInterval * (new Random().NextDouble() * 0.9 + 0.05);
|
2021-04-29 09:10:19 +00:00
|
|
|
}
|