Skip to content

Commit

Permalink
perf: ⚡ use semaphores to disallow new fetch while another is in prog…
Browse files Browse the repository at this point in the history
…ress (#10)
  • Loading branch information
JamesNZL committed May 18, 2023
1 parent 3235ac9 commit 7d2cc3f
Showing 1 changed file with 27 additions and 8 deletions.
35 changes: 27 additions & 8 deletions src/TogglTrack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ internal class TogglTrack
private Settings _settings { get; set; }

private TogglClient _client;
private (bool IsValid, string Token, SemaphoreSlim Semaphore) _lastToken = (false, string.Empty, new SemaphoreSlim(1, 1));
private (bool IsValid, string Token) _lastToken = (false, string.Empty);

private readonly (SemaphoreSlim Token, SemaphoreSlim Me, SemaphoreSlim RunningTimeEntries, SemaphoreSlim TimeEntries) _semaphores = (new SemaphoreSlim(1, 1), new SemaphoreSlim(1, 1), new SemaphoreSlim(1, 1), new SemaphoreSlim(1, 1));
private MemoryCache _cache = MemoryCache.Default;

private long? _selectedProjectId = -1;
Expand All @@ -43,8 +44,11 @@ internal TogglTrack(PluginInitContext context, Settings settings)
{
const string cacheKey = "Me";

if (!force && this._cache.Contains(cacheKey))
await this._semaphores.Me.WaitAsync();

if ((!force || this._semaphores.Me.CurrentCount == 0) && this._cache.Contains(cacheKey))
{
this._semaphores.Me.Release();
return (Me?)this._cache.Get(cacheKey);
}

Expand All @@ -58,11 +62,14 @@ internal TogglTrack(PluginInitContext context, Settings settings)
this._cache.Set(cacheKey, me, DateTimeOffset.Now.AddDays(3));
#pragma warning restore CS8604 // Possible null reference argument

this._semaphores.Me.Release();
return me;
}
catch (Exception exception)
{
this._context.API.LogException("TogglTrack", "Failed to fetch me", exception, "_GetMe");

this._semaphores.Me.Release();
return null;
}
}
Expand All @@ -71,26 +78,32 @@ internal TogglTrack(PluginInitContext context, Settings settings)
{
const string cacheKey = "RunningTimeEntry";

if (!force && this._cache.Contains(cacheKey))
await this._semaphores.RunningTimeEntries.WaitAsync();

if ((!force || this._semaphores.RunningTimeEntries.CurrentCount == 0) && this._cache.Contains(cacheKey))
{
this._semaphores.RunningTimeEntries.Release();
return (TimeEntry?)this._cache.Get(cacheKey);
}

try
{
this._context.API.LogInfo("TogglTrack", "Fetching running time entry", "_GetRunningTimeEntry");

var runningTimeEntry = await this._client.GetRunningTimeEntry();

#pragma warning disable CS8604 // Possible null reference argument
this._cache.Set(cacheKey, runningTimeEntry, DateTimeOffset.Now.AddSeconds(30));
#pragma warning restore CS8604 // Possible null reference argument

this._semaphores.RunningTimeEntries.Release();
return runningTimeEntry;
}
catch (Exception exception)
{
this._context.API.LogException("TogglTrack", "Failed to fetch running time entry", exception, "_GetRunningTimeEntry");

this._semaphores.RunningTimeEntries.Release();
return null;
}
}
Expand All @@ -99,8 +112,11 @@ internal TogglTrack(PluginInitContext context, Settings settings)
{
const string cacheKey = "TimeEntries";

await this._semaphores.TimeEntries.WaitAsync();

if (!force && this._cache.Contains(cacheKey))
{
this._semaphores.TimeEntries.Release();
return (List<TimeEntry>?)this._cache.Get(cacheKey);
}

Expand All @@ -115,11 +131,14 @@ internal TogglTrack(PluginInitContext context, Settings settings)
this._cache.Set(cacheKey, timeEntries, DateTimeOffset.Now.AddSeconds(30));
#pragma warning restore CS8604 // Possible null reference argument

this._semaphores.TimeEntries.Release();
return timeEntries;
}
catch (Exception exception)
{
this._context.API.LogException("TogglTrack", "Failed to fetch time entries", exception, "_GetTimeEntries");

this._semaphores.TimeEntries.Release();
return null;
}
}
Expand All @@ -142,17 +161,17 @@ internal async ValueTask<bool> VerifyApiToken()
return false;
}

await this._lastToken.Semaphore.WaitAsync();
await this._semaphores.Token.WaitAsync();

if (this._settings.ApiToken.Equals(this._lastToken.Token))
{
this._lastToken.Semaphore.Release();
this._semaphores.Token.Release();
return this._lastToken.IsValid;
}

if (string.IsNullOrWhiteSpace(this._settings.ApiToken))
{
this._lastToken.Semaphore.Release();
this._semaphores.Token.Release();
return this._lastToken.IsValid = false;
}

Expand All @@ -162,7 +181,7 @@ internal async ValueTask<bool> VerifyApiToken()
this._lastToken.IsValid = (await this._GetMe(true))?.api_token?.Equals(this._settings.ApiToken) ?? false;
this._lastToken.Token = this._settings.ApiToken;

this._lastToken.Semaphore.Release();
this._semaphores.Token.Release();
return this._lastToken.IsValid;
}

Expand Down

0 comments on commit 7d2cc3f

Please sign in to comment.