Skip to content

Commit ae0b5ce

Browse files
committed
Try to avoid flooding the thread pool with lavinprognoser requests that hold up other requests.
1 parent 54da797 commit ae0b5ce

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

SkredvarselGarminWeb/SkredvarselGarminWeb.Tests/LavinprognoserApiClientTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
using AwesomeAssertions;
77

8+
using Microsoft.Extensions.Caching.Memory;
9+
810
using NSubstitute;
911

1012
using Refit;
@@ -186,7 +188,8 @@ public async Task GetDetailedWarningsByArea_should_return_empty_when_area_id_is_
186188

187189
var sut = new LavinprognoserApiClient(
188190
wfsApi,
189-
websiteApi);
191+
websiteApi,
192+
new MemoryCache(new MemoryCacheOptions()));
190193

191194
var warnings = await sut.GetDetailedWarningsByArea(999, new DateOnly(2026, 3, 10), new DateOnly(2026, 3, 10));
192195

@@ -220,7 +223,8 @@ private static LavinprognoserApiClient CreateClient(
220223

221224
return new LavinprognoserApiClient(
222225
wfsApi,
223-
websiteApi);
226+
websiteApi,
227+
new MemoryCache(new MemoryCacheOptions()));
224228
}
225229

226230
private static Task<ApiResponse<LavinprognoserWebResponse>> CreateForecastResponse(

SkredvarselGarminWeb/SkredvarselGarminWeb/LavinprognoserApi/LavinprognoserApiClient.cs

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System.Text.Json;
22

3+
using Microsoft.Extensions.Caching.Memory;
4+
35
using Refit;
46

57
using SkredvarselGarminWeb.LavinprognoserApi.Models;
@@ -8,8 +10,11 @@ namespace SkredvarselGarminWeb.LavinprognoserApi;
810

911
public partial class LavinprognoserApiClient(
1012
ILavinprognoserWfsApi wfsApi,
11-
ILavinprognoserWebsiteApi websiteApi) : ILavinprognoserApi
13+
ILavinprognoserWebsiteApi websiteApi,
14+
IMemoryCache memoryCache) : ILavinprognoserApi
1215
{
16+
private static readonly SemaphoreSlim FetchSemaphore = new(3, 3);
17+
1318
public async Task<IEnumerable<WfsFeature<JsonElement>>> GetAllLocationPolygons()
1419
{
1520
var response = await GetAllWfsLocationPolygons("lavinprognoser:location", null);
@@ -43,25 +48,56 @@ private async Task<LavinprognoserDetailedWarning> ResolveWarningForDay(string sl
4348

4449
private async Task<LavinprognoserWebForecast?> FetchForecastForDate(string slug, DateOnly date)
4550
{
46-
var response = await GetForecastPage(slug, date);
47-
if (!response.IsSuccessStatusCode)
51+
var cacheKey = $"LavinprognoserForecast_{slug}_{date:yyyy-MM-dd}";
52+
if (memoryCache.TryGetValue<LavinprognoserWebForecast?>(cacheKey, out var cached))
4853
{
49-
return default;
54+
return cached;
5055
}
5156

52-
if (response.Content?.Content.Forecast != null)
57+
await FetchSemaphore.WaitAsync();
58+
try
5359
{
54-
return response.Content.Content.Forecast;
60+
if (memoryCache.TryGetValue<LavinprognoserWebForecast?>(cacheKey, out cached))
61+
{
62+
return cached;
63+
}
64+
65+
var response = await GetForecastPage(slug, date);
66+
if (!response.IsSuccessStatusCode)
67+
{
68+
return default;
69+
}
70+
71+
LavinprognoserWebForecast? forecast;
72+
if (response.Content?.Content.Forecast != null)
73+
{
74+
forecast = response.Content.Content.Forecast;
75+
}
76+
else
77+
{
78+
var redirectedSlug = SwedishForecastAreaRegistry.TryGetSlugFromRequestUri(response.RequestMessage?.RequestUri);
79+
if (redirectedSlug == null || redirectedSlug == slug)
80+
{
81+
forecast = response.Content?.Content.Forecast;
82+
}
83+
else
84+
{
85+
var redirectedResponse = await GetForecastPage(redirectedSlug, date);
86+
forecast = redirectedResponse.Content?.Content.Forecast;
87+
}
88+
}
89+
90+
memoryCache.Set(cacheKey, forecast, new MemoryCacheEntryOptions
91+
{
92+
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
93+
});
94+
95+
return forecast;
5596
}
56-
57-
var redirectedSlug = SwedishForecastAreaRegistry.TryGetSlugFromRequestUri(response.RequestMessage?.RequestUri);
58-
if (redirectedSlug == null || redirectedSlug == slug)
97+
finally
5998
{
60-
return response.Content?.Content.Forecast;
99+
FetchSemaphore.Release();
61100
}
62-
63-
var redirectedResponse = await GetForecastPage(redirectedSlug, date);
64-
return redirectedResponse.Content?.Content.Forecast;
65101
}
66102

67103
private Task<ApiResponse<WfsFeatureCollection<JsonElement>>> GetAllWfsLocationPolygons(string typeName, string? cqlFilter) =>

0 commit comments

Comments
 (0)