PluralKit/Myriad/Gateway/State/HeartbeatWorker.cs

58 lines
1.6 KiB
C#
Raw Normal View History

namespace Myriad.Gateway.State;
2021-04-29 09:10:19 +00:00
public class HeartbeatWorker: IAsyncDisposable
2021-04-29 09:10:19 +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
{
await Stop();
}
2021-08-27 15:03:47 +00:00
public async ValueTask Start(TimeSpan heartbeatInterval, Func<Task> callback)
{
if (_worker != null)
await Stop();
2021-04-29 09:10:19 +00:00
CurrentHeartbeatInterval = heartbeatInterval;
_workerCts = new CancellationTokenSource();
_worker = Worker(heartbeatInterval, callback, _workerCts.Token);
}
2021-04-29 09:10:19 +00:00
public async ValueTask Stop()
{
if (_worker == null)
return;
2021-04-29 09:10:19 +00:00
_workerCts?.Cancel();
try
2021-04-29 09:10:19 +00:00
{
await _worker;
2021-04-29 09:10:19 +00:00
}
catch (TaskCanceledException) { }
2021-08-27 15:03:47 +00:00
_worker?.Dispose();
_workerCts?.Dispose();
_worker = null;
CurrentHeartbeatInterval = null;
}
2021-04-29 09:10:19 +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
while (!ct.IsCancellationRequested)
2021-04-29 09:10:19 +00:00
{
await callback();
await Task.Delay(heartbeatInterval, ct);
2021-04-29 09:10:19 +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
}