| | | 1 | | using GistBackend.Handlers; |
| | | 2 | | |
| | | 3 | | namespace GistBackend.Utils; |
| | | 4 | | |
| | | 5 | | public interface IGistDebouncer |
| | | 6 | | { |
| | | 7 | | bool IsReady(int gistId, DateTime updated); |
| | | 8 | | } |
| | | 9 | | |
| | 11 | 10 | | public class GistDebouncer(IDateTimeHandler dateTimeHandler) : IGistDebouncer |
| | | 11 | | { |
| | 11 | 12 | | private readonly Dictionary<int, DateTime> _readyTimesByGistId = new(); |
| | 1 | 13 | | private static readonly Random Random = new(); |
| | | 14 | | |
| | | 15 | | public bool IsReady(int gistId, DateTime updated) |
| | | 16 | | { |
| | 21 | 17 | | if (_readyTimesByGistId.TryGetValue(gistId, out var readyTime)) |
| | | 18 | | { |
| | 15 | 19 | | if (readyTime > dateTimeHandler.GetUtcNow()) return false; |
| | 5 | 20 | | DebounceGist(gistId, updated); |
| | 5 | 21 | | return true; |
| | | 22 | | } |
| | 11 | 23 | | DebounceGist(gistId, updated); |
| | 11 | 24 | | return false; |
| | | 25 | | } |
| | | 26 | | |
| | | 27 | | private void DebounceGist(int gistId, DateTime updated) |
| | | 28 | | { |
| | 16 | 29 | | _readyTimesByGistId[gistId] = CalculateReadyTime(updated); |
| | 16 | 30 | | } |
| | | 31 | | |
| | | 32 | | private DateTime CalculateReadyTime(DateTime updated) |
| | | 33 | | { |
| | 16 | 34 | | var now = dateTimeHandler.GetUtcNow(); |
| | 16 | 35 | | var age = now - updated; |
| | | 36 | | |
| | | 37 | | TimeSpan meanDebounceDuration; |
| | 18 | 38 | | if (age < TimeSpan.FromHours(1)) meanDebounceDuration = TimeSpan.FromMinutes(30); |
| | 19 | 39 | | else if (age < TimeSpan.FromHours(6)) meanDebounceDuration = TimeSpan.FromHours(1); |
| | 12 | 40 | | else if (age < TimeSpan.FromDays(1)) meanDebounceDuration = TimeSpan.FromHours(3); |
| | 9 | 41 | | else if (age < TimeSpan.FromDays(7)) meanDebounceDuration = TimeSpan.FromHours(6); |
| | 3 | 42 | | else meanDebounceDuration = TimeSpan.FromDays(1); |
| | | 43 | | |
| | | 44 | | // Generate random jitter between -meanDebounceDuration/2 and +meanDebounceDuration/2 |
| | 16 | 45 | | var halfDuration = meanDebounceDuration / 2; |
| | 16 | 46 | | var randomFactor = Random.NextDouble() * 2 - 1; // [-1, 1] |
| | 16 | 47 | | var jitter = halfDuration * randomFactor; |
| | | 48 | | |
| | 16 | 49 | | return now + meanDebounceDuration + jitter; |
| | | 50 | | } |
| | | 51 | | } |