Skip to content

Commit

Permalink
Merge branch 'fix-stampede' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
billhong-just committed Sep 25, 2023
2 parents c74ad32 + 12159e9 commit 273e147
Show file tree
Hide file tree
Showing 21 changed files with 245 additions and 40 deletions.
8 changes: 4 additions & 4 deletions build/version.props
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project>
<PropertyGroup>
<EasyCachingCorePackageVersion>1.9.1</EasyCachingCorePackageVersion>
<EasyCachingCorePackageVersion>1.9.2</EasyCachingCorePackageVersion>
<EasyCachingMemcachedPackageVersion>1.9.1</EasyCachingMemcachedPackageVersion>
<EasyCachingRedisPackageVersion>1.9.1</EasyCachingRedisPackageVersion>
<EasyCachingRedisPackageVersion>1.9.2</EasyCachingRedisPackageVersion>
<EasyCachingSQLitePackageVersion>1.9.1</EasyCachingSQLitePackageVersion>
<EasyCachingInMemoryPackageVersion>1.9.1</EasyCachingInMemoryPackageVersion>
<EasyCachingHybridPackageVersion>1.9.1</EasyCachingHybridPackageVersion>
<EasyCachingInMemoryPackageVersion>1.9.2</EasyCachingInMemoryPackageVersion>
<EasyCachingHybridPackageVersion>1.9.2</EasyCachingHybridPackageVersion>
<EasyCachingAspectCorePackageVersion>1.9.1</EasyCachingAspectCorePackageVersion>
<EasyCachingCastlePackageVersion>1.9.1</EasyCachingCastlePackageVersion>
<EasyCachingResponseCachingPackageVersion>1.9.1</EasyCachingResponseCachingPackageVersion>
Expand Down
1 change: 1 addition & 0 deletions bus/EasyCaching.Bus.Redis/EasyCaching.Bus.Redis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<AssemblyName>Just.$(MSBuildProjectName)</AssemblyName>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<AssemblyName>Just.$(MSBuildProjectName)</AssemblyName>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

public partial class DefaultCSRedisCachingProvider : EasyCachingAbstractProvider
{
public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)

Check warning on line 13 in src/EasyCaching.CSRedis/DefaultCSRedisCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build on windows-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 13 in src/EasyCaching.CSRedis/DefaultCSRedisCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / Build and upload artifact

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 13 in src/EasyCaching.CSRedis/DefaultCSRedisCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / Build and upload artifact

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 13 in src/EasyCaching.CSRedis/DefaultCSRedisCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build and test on ubuntu-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 13 in src/EasyCaching.CSRedis/DefaultCSRedisCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build and test on ubuntu-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
throw new NotImplementedException();
}
/// <summary>
/// Existses the async.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/EasyCaching.Core/EasyCaching.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<AssemblyName>Just.$(MSBuildProjectName)</AssemblyName>
</PropertyGroup>

<ItemGroup>
Expand Down
61 changes: 61 additions & 0 deletions src/EasyCaching.Core/EasyCachingAbstractProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ protected EasyCachingAbstractProvider(IDistributedLockFactory lockFactory, BaseP
public abstract IDictionary<string, CacheValue<T>> BaseGetAll<T>(IEnumerable<string> cacheKeys);
public abstract Task<IDictionary<string, CacheValue<T>>> BaseGetAllAsync<T>(IEnumerable<string> cacheKeys, CancellationToken cancellationToken = default);
public abstract Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, TimeSpan expiration, CancellationToken cancellationToken = default);
public abstract Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default);
public abstract Task<object> BaseGetAsync(string cacheKey, Type type, CancellationToken cancellationToken = default);
public abstract Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, CancellationToken cancellationToken = default);
public abstract IDictionary<string, CacheValue<T>> BaseGetByPrefix<T>(string prefix);
Expand Down Expand Up @@ -363,6 +364,66 @@ public async Task<IDictionary<string, CacheValue<T>>> GetAllAsync<T>(IEnumerable
}
}

public async Task<CacheValue<T>> GetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)
{
var operationId = s_diagnosticListener.WriteGetCacheBefore(new BeforeGetRequestEventData(CachingProviderType.ToString(), Name, nameof(GetAsync), new[] { cacheKey }));
Exception e = null;
try
{
if (_lockFactory == null) return await BaseGetAsync<T>(cacheKey, dataRetriever, expirationRetriever, cancellationToken);

var value = await BaseGetAsync<T>(cacheKey, cancellationToken);
if (value.HasValue) return value;

var @lock = _lockFactory.CreateLock(Name, $"{cacheKey}_Lock");
try
{
if (!await @lock.LockAsync(_options.SleepMs, cancellationToken)) throw new TimeoutException();

value = await BaseGetAsync<T>(cacheKey, cancellationToken);
if (value.HasValue) return value;

var task = dataRetriever();
if (!task.IsCompleted &&
await Task.WhenAny(task, Task.Delay(_options.LockMs, cancellationToken)) != task)
throw new TimeoutException();

var item = await task;
if (item != null || _options.CacheNulls)
{
TimeSpan expiration = await expirationRetriever();
await BaseSetAsync(cacheKey, item, expiration, cancellationToken);

return new CacheValue<T>(item, true);
}
else
{
return CacheValue<T>.NoValue;
}
}
finally
{
await @lock.DisposeAsync();
}
}
catch (Exception ex)
{
e = ex;
throw;
}
finally
{
if (e != null)
{
s_diagnosticListener.WriteGetCacheError(operationId, e);
}
else
{
s_diagnosticListener.WriteGetCacheAfter(operationId);
}
}
}

public async Task<CacheValue<T>> GetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, TimeSpan expiration, CancellationToken cancellationToken = default)
{
var operationId = s_diagnosticListener.WriteGetCacheBefore(new BeforeGetRequestEventData(CachingProviderType.ToString(), Name, nameof(GetAsync), new[] { cacheKey }, expiration));
Expand Down
11 changes: 11 additions & 0 deletions src/EasyCaching.Core/IEasyCachingProviderBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ public interface IEasyCachingProviderBase
/// <typeparam name="T">The 1st type parameter.</typeparam>
Task<CacheValue<T>> GetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, TimeSpan expiration, CancellationToken cancellationToken = default);

/// <summary>
/// Gets the specified cacheKey, dataRetriever and expirationRetriever async.
/// </summary>
/// <returns>The async.</returns>
/// <param name="cacheKey">Cache key.</param>
/// <param name="dataRetriever">Data retriever.</param>
/// <param name="expirationRetriever">Expiration retriever.</param>
/// <param name="cancellationToken"></param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
Task<CacheValue<T>> GetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default);

/// <summary>
/// Removes cached item by cachekey's prefix.
/// </summary>
Expand Down
6 changes: 5 additions & 1 deletion src/EasyCaching.Disk/DefaultDiskCachingProvider.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
using Microsoft.Extensions.Logging;

public partial class DefaultDiskCachingProvider : EasyCachingAbstractProvider
{
{
public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)

Check warning on line 14 in src/EasyCaching.Disk/DefaultDiskCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / Build and upload artifact

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 14 in src/EasyCaching.Disk/DefaultDiskCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / Build and upload artifact

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
throw new NotImplementedException();
}
public override async Task<bool> BaseExistsAsync(string cacheKey, CancellationToken cancellationToken = default)
{
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ namespace EasyCaching.FasterKv
{
public partial class DefaultFasterKvCachingProvider
{
public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)

Check warning on line 12 in src/EasyCaching.FasterKv/DefaultFasterKvCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build on windows-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 12 in src/EasyCaching.FasterKv/DefaultFasterKvCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build on windows-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 12 in src/EasyCaching.FasterKv/DefaultFasterKvCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / Build and upload artifact

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 12 in src/EasyCaching.FasterKv/DefaultFasterKvCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build and test on ubuntu-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
throw new NotImplementedException();
}
public override async Task<bool> BaseExistsAsync(string cacheKey, CancellationToken cancellationToken = default)
{
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
Expand Down
1 change: 1 addition & 0 deletions src/EasyCaching.HybridCache/EasyCaching.HybridCache.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<AssemblyName>Just.$(MSBuildProjectName)</AssemblyName>
</PropertyGroup>

<ItemGroup>
Expand Down
69 changes: 34 additions & 35 deletions src/EasyCaching.HybridCache/HybridCachingProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,42 +304,26 @@ public CacheValue<T> Get<T>(string cacheKey)
public async Task<CacheValue<T>> GetAsync<T>(string cacheKey, CancellationToken cancellationToken = default)
{
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

var cacheValue = await _localCache.GetAsync<T>(cacheKey, cancellationToken);

if (cacheValue.HasValue)
{
return cacheValue;
}

LogMessage($"local cache can not get the value of {cacheKey}");

try
{
cacheValue = await _distributedCache.GetAsync<T>(cacheKey, cancellationToken);
}
catch (Exception ex)
{
LogMessage($"distributed cache get error, [{cacheKey}]", ex);

if (_options.ThrowIfDistributedCacheError)
var result = await _localCache.GetAsync(
cacheKey,
async () =>
{
throw;
}
}

if (cacheValue.HasValue)
{
TimeSpan ts = await GetExpirationAsync(cacheKey, cancellationToken);

await _localCache.SetAsync(cacheKey, cacheValue.Value, ts, cancellationToken);

return cacheValue;
}

LogMessage($"distributed cache can not get the value of {cacheKey}");

return CacheValue<T>.NoValue;
var value = default(T);
try
{
value = (await _distributedCache.GetAsync<T>(cacheKey, cancellationToken)).Value;
}
catch (Exception ex)
{
LogMessage($"distributed cache get error, [{cacheKey}]", ex);
if (_options.ThrowIfDistributedCacheError)
throw;
}
return value;
},
() => GetExpirationAsync(cacheKey, cancellationToken),
cancellationToken);
return result;
}

/// <summary>
Expand Down Expand Up @@ -780,6 +764,21 @@ public async Task<CacheValue<T>> GetAsync<T>(string cacheKey, Func<Task<T>> data
return CacheValue<T>.NoValue;
}

/// <summary>
/// Gets the specified cacheKey, dataRetriever and expirationRetriever async.
/// </summary>
/// <returns>The async.</returns>
/// <param name="cacheKey">Cache key.</param>
/// <param name="dataRetriever">Data retriever.</param>
/// <param name="expirationRetriever">Expiration retriever.</param>
/// <param name="cancellationToken"></param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public async Task<CacheValue<T>> GetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)

Check warning on line 776 in src/EasyCaching.HybridCache/HybridCachingProvider.cs

View workflow job for this annotation

GitHub Actions / build on windows-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 776 in src/EasyCaching.HybridCache/HybridCachingProvider.cs

View workflow job for this annotation

GitHub Actions / build on windows-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 776 in src/EasyCaching.HybridCache/HybridCachingProvider.cs

View workflow job for this annotation

GitHub Actions / Build and upload artifact

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 776 in src/EasyCaching.HybridCache/HybridCachingProvider.cs

View workflow job for this annotation

GitHub Actions / Build and upload artifact

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 776 in src/EasyCaching.HybridCache/HybridCachingProvider.cs

View workflow job for this annotation

GitHub Actions / build and test on ubuntu-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 776 in src/EasyCaching.HybridCache/HybridCachingProvider.cs

View workflow job for this annotation

GitHub Actions / build and test on ubuntu-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
// TiSvc 沒用到,不實作
throw new NotImplementedException();
}

/// <summary>
/// Removes the by prefix.
/// </summary>
Expand Down
42 changes: 42 additions & 0 deletions src/EasyCaching.InMemory/DefaultInMemoryCachingProvider.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,48 @@ public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<
}
}

public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)
{
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
bool getLock = false;
do
{
var result = _cache.Get<T>(cacheKey);
if (result.HasValue)
return result;
getLock = _cache.Add($"{cacheKey}_Lock", 1, TimeSpan.FromMilliseconds(_options.LockMs));
if (!getLock)
await Task.Delay(_options.SleepMs, cancellationToken);
}
while (!getLock);
try
{
var res = await dataRetriever();

if (res != null || _options.CacheNulls)
{
TimeSpan expiration = await expirationRetriever();
await SetAsync(cacheKey, res, expiration, cancellationToken);
//remove mutex key
_cache.Remove($"{cacheKey}_Lock");

return new CacheValue<T>(res, true);
}
else
{
//remove mutex key
_cache.Remove($"{cacheKey}_Lock");
return CacheValue<T>.NoValue;
}
}
catch
{
//remove mutex key
_cache.Remove($"{cacheKey}_Lock");
throw;
}
}

/// <summary>
/// Gets the specified cacheKey async.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/EasyCaching.InMemory/EasyCaching.InMemory.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<AssemblyName>Just.$(MSBuildProjectName)</AssemblyName>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 4 additions & 0 deletions src/EasyCaching.LiteDB/DefaultLiteDBCachingProvider.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
/// </summary>
public partial class DefaultLiteDBCachingProvider : EasyCachingAbstractProvider
{
public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)

Check warning on line 15 in src/EasyCaching.LiteDB/DefaultLiteDBCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build on windows-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 15 in src/EasyCaching.LiteDB/DefaultLiteDBCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build and test on ubuntu-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
throw new NotImplementedException();
}
/// <summary>
/// Existses the specified cacheKey async.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
/// </summary>
public partial class DefaultMemcachedCachingProvider : EasyCachingAbstractProvider
{
public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)

Check warning on line 16 in src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build on windows-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 16 in src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build on windows-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 16 in src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / Build and upload artifact

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 16 in src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build and test on ubuntu-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 16 in src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.Async.cs

View workflow job for this annotation

GitHub Actions / build and test on ubuntu-latest

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the specified cacheKey, dataRetriever and expiration async.
/// </summary>
Expand Down
47 changes: 47 additions & 0 deletions src/EasyCaching.Redis/DefaultRedisCachingProvider.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,53 @@ public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<
}
}

public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, Func<Task<TimeSpan>> expirationRetriever, CancellationToken cancellationToken = default)
{
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

var result = await _cache.StringGetAsync(cacheKey);
if (!result.IsNull)
{
CacheStats.OnHit();

if (_options.EnableLogging)
_logger?.LogInformation($"Cache Hit : cachekey = {cacheKey}");

var value = _serializer.Deserialize<T>(result);
return new CacheValue<T>(value, true);
}

CacheStats.OnMiss();

if (_options.EnableLogging)
_logger?.LogInformation($"Cache Missed : cachekey = {cacheKey}");

var flag = await _cache.StringSetAsync($"{cacheKey}_Lock", 1, TimeSpan.FromMilliseconds(_options.LockMs), When.NotExists);

if (!flag)
{
await Task.Delay(_options.SleepMs, cancellationToken);
return await GetAsync(cacheKey, dataRetriever, expirationRetriever, cancellationToken);
}

var item = await dataRetriever();
if (item != null || _options.CacheNulls)
{
TimeSpan expiration = await expirationRetriever();
await SetAsync(cacheKey, item, expiration, cancellationToken);

//remove mutex key
await _cache.KeyDeleteAsync($"{cacheKey}_Lock");
return new CacheValue<T>(item, true);
}
else
{
//remove mutex key
await _cache.KeyDeleteAsync($"{cacheKey}_Lock");
return CacheValue<T>.NoValue;
}
}

/// <summary>
/// Gets the specified cacheKey async.
/// </summary>
Expand Down
Loading

0 comments on commit 273e147

Please sign in to comment.