{"id":7222,"date":"2023-01-19T11:47:43","date_gmt":"2023-01-19T10:47:43","guid":{"rendered":"https:\/\/solidt.eu\/site\/?p=7222"},"modified":"2023-01-19T11:47:43","modified_gmt":"2023-01-19T10:47:43","slug":"c-threaded-throttle-api-call","status":"publish","type":"post","link":"https:\/\/solidt.eu\/site\/c-threaded-throttle-api-call\/","title":{"rendered":"C# Threaded throttle (api call)"},"content":{"rendered":"\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"csharp\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">public class OverviewController : BaseApiController\n{\n    private static readonly ThrottleDictionary throttleDictionary = new();\n    private readonly TimeSpan throttleTime = TimeSpan.FromSeconds(30);\n\n    [HttpGet(\"api\/day\/{date}\")]\n    [ApiCallRight(\"api.get.day\")]\n    public async Task&lt;VmCalendarList> GetDayOverview(DateTime date, bool isChanged = false)\n    {\n        var cacheKey = $\"dayoverview-{date:yyyy-MM-dd}\";\n        var throttle = throttleDictionary.Get(cacheKey, throttleTime);\n        var value = (VmCalendarList)throttle.Value;\n\n        if (!isChanged &amp;&amp; !throttle.CanFire() &amp;&amp; value != null) return value;\n        \n        await throttle.Build(async () =>\n        {\n            var absenceInfo = await DomainPorts.OverviewService.DayOverview(date);\n            var result = VmCalendarList.FromDomain(absenceInfo);\n            throttle.Value = result;\n        });\n        return (VmCalendarList)throttle.Value;\n    }\n}\n\n\npublic class ThrottleDictionary\n{\n    private readonly ConcurrentDictionary&lt;string, Throttle> keyValuePairs = new();\n    \n    public Throttle Get(string key, TimeSpan throttleTime)\n    {\n        if (cleanupThrottle.CanFire()) Cleanup();\n        return keyValuePairs.GetOrAdd(key, (key) => new Throttle(throttleTime));\n    }\n\n    private static readonly TimeSpan cleanupTime = TimeSpan.FromHours(1);\n    private readonly Throttle cleanupThrottle = new(cleanupTime);\n\n    private void Cleanup()\n    {\n        var keysToRemove = keyValuePairs.Where(x => x.Value.LastUsed() &lt; DateTime.Now.Subtract(cleanupTime)).Select(x => x.Key);\n        foreach(var key in keysToRemove) {\n            keyValuePairs.Remove(key, out _);\n        }\n    }\n}\n\npublic class Throttle\n{\n    public Throttle(TimeSpan throttleTime)\n    {\n        ThrottleTime = throttleTime;\n    }\n    private DateTime? Last = null;\n    private readonly TimeSpan ThrottleTime;\n    private readonly object Locker = new();\n\n    public DateTime? LastUsed() => Last ?? DateTime.Now;\n\n    public object Value { get; set; }\n\n    public Task BuildTask;\n    public async Task Build(Func&lt;Task> fn) \n    {\n        if (BuildTask != null)\n        {\n            await BuildTask;\n            return;\n        }\n        try\n        {\n            BuildTask = fn();\n            await BuildTask;\n        }\n        finally\n        {\n            BuildTask = null;\n        }\n    }\n\n    public void Update()\n    {\n        Last = DateTime.Now;\n    }\n\n    public bool CanFire()\n    {\n        lock(Locker) \n        { \n            bool canFire = Last == null || (DateTime.Now - Last).Value > ThrottleTime;\n            if (canFire) Update();\n            return canFire;\n        }\n    }\n}\n\n<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7222","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/7222","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/comments?post=7222"}],"version-history":[{"count":1,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/7222\/revisions"}],"predecessor-version":[{"id":7223,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/7222\/revisions\/7223"}],"wp:attachment":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/media?parent=7222"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/categories?post=7222"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/tags?post=7222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}