Skip to content

Commit 7e8726a

Browse files
Merge pull request #102 from martijnboland/85-distributedcache
Use IDistributedCache instead of IMemoryCache to support multi-instan…
2 parents 137812a + 03c2bf7 commit 7e8726a

File tree

4 files changed

+71
-21
lines changed

4 files changed

+71
-21
lines changed

src/AppText.Localization/AppTextBridge.cs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using AppText.Features.Application;
22
using AppText.Features.ContentManagement;
3+
using AppText.Shared.Extensions;
34
using AppText.Shared.Infrastructure;
45
using AppText.Storage;
6+
using Microsoft.Extensions.Caching.Distributed;
57
using Microsoft.Extensions.Caching.Memory;
68
using Microsoft.Extensions.DependencyInjection;
79
using Microsoft.Extensions.Logging;
@@ -25,13 +27,13 @@ public class AppTextBridge
2527

2628
private readonly ILogger<AppTextBridge> _logger;
2729
private readonly AppTextLocalizationOptions _options;
28-
private readonly IMemoryCache _cache;
30+
private readonly IDistributedCache _cache;
2931
private readonly IServiceProvider _serviceProvider;
3032
private ISet<string> _cacheKeys;
3133

3234
public AppTextBridge(
3335
IServiceProvider serviceProvider,
34-
IMemoryCache cache,
36+
IDistributedCache cache,
3537
IOptions<AppTextLocalizationOptions> options,
3638
ILogger<AppTextBridge> logger
3739
)
@@ -83,27 +85,34 @@ private Dictionary<string, string> GetTranslationsDictionary(string culture)
8385
// When culture is invariant, the name is an empty string. Use the default language in that case.
8486
if (culture == String.Empty)
8587
{
86-
var currentApp = _cache.GetOrCreate(AppCacheKey, c => new Lazy<App>(LoadApp, LazyThreadSafetyMode.ExecutionAndPublication)).Value;
88+
var currentApp = _cache.Get<App>(AppCacheKey);
89+
if (currentApp == null)
90+
{
91+
currentApp = LoadApp();
92+
_cache.Set(AppCacheKey, currentApp);
93+
}
8794
if (currentApp == null)
8895
{
8996
throw new InvalidOperationException($"Can not get the translations because the AppText app {_options.AppId} is not found");
9097
}
9198
culture = currentApp.DefaultLanguage;
9299
}
93100

94-
var cachedDictionary = _cache.GetOrCreate(CacheKeyPrefix + culture, c => new Lazy<Dictionary<string, string>>(() =>
101+
var cacheKey = CacheKeyPrefix + culture;
102+
var cachedDictionary = _cache.Get<Dictionary<string, string>>(cacheKey);
103+
if (cachedDictionary == null)
95104
{
96105
_logger.LogInformation("Initializing translations dictionary for culture {0}", culture);
97-
var dictionary = new Dictionary<string, string>();
98-
LoadTranslationsIntoDictionary(culture, dictionary);
99-
if (! _cacheKeys.Contains(c.Key))
106+
cachedDictionary = new Dictionary<string, string>();
107+
LoadTranslationsIntoDictionary(culture, cachedDictionary);
108+
if (! _cacheKeys.Contains(cacheKey))
100109
{
101-
_cacheKeys.Add(c.Key.ToString());
110+
_cacheKeys.Add(cacheKey);
102111
}
103-
return dictionary;
104-
}, LazyThreadSafetyMode.ExecutionAndPublication));
112+
_cache.Set(cacheKey, cachedDictionary);
113+
}
105114

106-
return cachedDictionary.Value;
115+
return cachedDictionary;
107116
}
108117

109118
private App LoadApp()

src/AppText/Configuration/AppTextBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ private void RegisterCoreServices()
9191
() => sp.GetRequiredService<IScopedServiceFactory>().GetService<IContentStore>());
9292

9393
// Cache
94-
Services.AddMemoryCache();
94+
Services.AddDistributedMemoryCache();
9595

9696
// ApiKey authentication scheme
9797
var authenticationBuilder = Services.AddAuthentication();

src/AppText/Features/GraphQL/SchemaResolver.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using AppText.Storage;
1+
using AppText.Shared.Extensions;
2+
using AppText.Storage;
23
using GraphQL.Types;
4+
using Microsoft.Extensions.Caching.Distributed;
35
using Microsoft.Extensions.Caching.Memory;
46
using Microsoft.Extensions.Logging;
57
using System;
@@ -12,12 +14,12 @@ public class SchemaResolver
1214
private readonly ILogger<SchemaResolver> _logger;
1315
private readonly Func<IContentStore> _getContentStore;
1416
private readonly Func<IApplicationStore> _getApplicationStore;
15-
private readonly IMemoryCache _memoryCache;
17+
private readonly IDistributedCache _cache;
1618

17-
public SchemaResolver(ILogger<SchemaResolver> logger, IMemoryCache memoryCache, Func<IApplicationStore> getApplicationStore, Func<IContentStore> getContentStore)
19+
public SchemaResolver(ILogger<SchemaResolver> logger, IDistributedCache cache, Func<IApplicationStore> getApplicationStore, Func<IContentStore> getContentStore)
1820
{
1921
_logger = logger;
20-
_memoryCache = memoryCache;
22+
_cache = cache;
2123
_getApplicationStore = getApplicationStore;
2224
_getContentStore = getContentStore;
2325
}
@@ -29,20 +31,21 @@ public SchemaResolver(ILogger<SchemaResolver> logger, IMemoryCache memoryCache,
2931
public async Task<ISchema> Resolve(string appId)
3032
{
3133
var cacheKey = $"Schema_{appId}";
32-
33-
return await _memoryCache.GetOrCreateAsync(cacheKey, async cacheEntry =>
34+
var schema = _cache.Get<ISchema>(cacheKey);
35+
if (schema == null)
3436
{
3537
_logger.LogInformation("GraphQL schema for app {0} is not found in the cache. Creating new instance...", appId);
36-
return await CreateSchema(appId);
37-
});
38+
schema = await CreateSchema(appId);
39+
}
40+
return schema;
3841
}
3942

4043
public void Clear(string appId)
4144
{
4245
_logger.LogInformation("Clearing GraphQL schema for app {0}", appId);
4346

4447
var cacheKey = $"Schema_{appId}";
45-
_memoryCache.Remove(cacheKey);
48+
_cache.Remove(cacheKey);
4649
}
4750

4851
private async Task<Schema> CreateSchema(string appId)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using Microsoft.Extensions.Caching.Distributed;
2+
using Newtonsoft.Json;
3+
using System;
4+
using System.Threading.Tasks;
5+
6+
namespace AppText.Shared.Extensions
7+
{
8+
public static class IDistributedCacheExtensions
9+
{
10+
public static void Set<T>(this IDistributedCache cache,
11+
string cacheKey,
12+
T data,
13+
TimeSpan? absoluteExpireTime = null,
14+
TimeSpan? slidingExpireTime = null)
15+
{
16+
var options = new DistributedCacheEntryOptions
17+
{
18+
AbsoluteExpirationRelativeToNow = absoluteExpireTime ?? TimeSpan.FromMinutes(1),
19+
SlidingExpiration = slidingExpireTime
20+
};
21+
22+
var jsonData = JsonConvert.SerializeObject(data);
23+
cache.SetString(cacheKey, jsonData, options);
24+
}
25+
26+
public static T Get<T>(this IDistributedCache cache, string cacheKey)
27+
{
28+
var jsonData = cache.GetString(cacheKey);
29+
30+
if (jsonData is null)
31+
{
32+
return default;
33+
}
34+
35+
return JsonConvert.DeserializeObject<T>(jsonData);
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)