Skip to content

Commit 635a869

Browse files
committed
feat:add etcdCaching and modify demo add etcddemo and etcdLockDemo
1 parent 467375a commit 635a869

File tree

14 files changed

+426
-71
lines changed

14 files changed

+426
-71
lines changed

sample/EasyCaching.Demo.Locks/Controllers/LocksController.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,34 @@ public async Task MemoryLockingOperation(int millisecondsTimeout)
6767
await memoryLock.ReleaseAsync();
6868
}
6969
}
70+
71+
[HttpPost("etcd-locking")]
72+
public async Task EtcdLockingOperation(int millisecondsTimeout)
73+
{
74+
using var distributedLock = _distributedLockFactory.CreateLock("DefaultEtcd", "YourKey");
75+
76+
try
77+
{
78+
await distributedLock.LockAsync(millisecondsTimeout);
79+
if (await distributedLock.LockAsync(millisecondsTimeout))
80+
{
81+
// Simulate operation
82+
Thread.Sleep(2000);
83+
}
84+
else
85+
{
86+
// Proper error
87+
}
88+
}
89+
catch (Exception ex)
90+
{
91+
// log error
92+
throw new Exception("Exception", ex);
93+
}
94+
finally
95+
{
96+
// release lock at the end
97+
await distributedLock.ReleaseAsync();
98+
}
99+
}
70100
}

sample/EasyCaching.Demo.Locks/EasyCaching.Demo.Locks.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<ProjectReference Include="..\..\bus\EasyCaching.Bus.Redis\EasyCaching.Bus.Redis.csproj" />
1313
<ProjectReference Include="..\..\interceptor\EasyCaching.Interceptor.AspectCore\EasyCaching.Interceptor.AspectCore.csproj" />
1414
<ProjectReference Include="..\..\serialization\EasyCaching.Serialization.Json\EasyCaching.Serialization.Json.csproj" />
15+
<ProjectReference Include="..\..\src\EasyCaching.Etcd\EasyCaching.Etcd.csproj" />
1516
<ProjectReference Include="..\..\src\EasyCaching.HybridCache\EasyCaching.HybridCache.csproj" />
1617
<ProjectReference Include="..\..\src\EasyCaching.InMemory\EasyCaching.InMemory.csproj" />
1718
<ProjectReference Include="..\..\src\EasyCaching.Redis\EasyCaching.Redis.csproj" />
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
global using EasyCaching.Core.Configurations;
22
global using EasyCaching.Core.DistributedLock;
33
global using Microsoft.AspNetCore.Mvc;
4-
global using EasyCaching.Redis.DistributedLock;
4+
global using EasyCaching.Redis.DistributedLock;
5+
global using EasyCaching.Etcd.DistributedLock;

sample/EasyCaching.Demo.Locks/Program.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Newtonsoft.Json;
2+
13
var builder = WebApplication.CreateBuilder(args);
24

35
// Add services to the container.
@@ -23,6 +25,19 @@
2325
})
2426
.WithJson()//with josn serialization
2527
.UseRedisLock(); // use distributed lock
28+
29+
// use etcd cache
30+
option.UseEtcd(options =>
31+
{
32+
options.Address = "http://121.196.220.148:12379";
33+
options.Timeout = 30000;
34+
options.LockMs = 3000;
35+
options.SerializerName = "json";
36+
}).WithJson(jsonSerializerSettingsConfigure: x =>
37+
{
38+
x.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
39+
x.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
40+
}, "json").UseEtcdLock(); ;
2641
});
2742

2843
#region How Inject Distributed and Memory lock
@@ -33,6 +48,9 @@
3348
// inject to use memory lock
3449
builder.Services.AddSingleton<IDistributedLockFactory, MemoryLockFactory>();
3550

51+
// inject to use memory lock
52+
builder.Services.AddSingleton<IDistributedLockFactory, EtcdLockFactory>();
53+
3654
#endregion
3755

3856
var app = builder.Build();

sample/EasyCaching.Demo.Providers/EasyCaching.Demo.Providers.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
<ItemGroup>
88
<ProjectReference Include="..\..\bus\EasyCaching.Bus.ConfluentKafka\EasyCaching.Bus.ConfluentKafka.csproj" />
99
<ProjectReference Include="..\..\bus\EasyCaching.Bus.Zookeeper\EasyCaching.Bus.Zookeeper.csproj" />
10+
<ProjectReference Include="..\..\serialization\EasyCaching.Serialization.Json\EasyCaching.Serialization.Json.csproj" />
11+
<ProjectReference Include="..\..\src\EasyCaching.Etcd\EasyCaching.Etcd.csproj" />
1012
<ProjectReference Include="..\..\src\EasyCaching.FasterKv\EasyCaching.FasterKv.csproj" />
1113
<ProjectReference Include="..\..\src\EasyCaching.Redis\EasyCaching.Redis.csproj" />
1214
<ProjectReference Include="..\..\src\EasyCaching.Memcached\EasyCaching.Memcached.csproj" />

sample/EasyCaching.Demo.Providers/Startup.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.Extensions.DependencyInjection;
99
using Microsoft.Extensions.Hosting;
1010
using Microsoft.Extensions.Logging;
11+
using Newtonsoft.Json;
1112

1213
public class Startup
1314
{
@@ -69,6 +70,18 @@ public void ConfigureServices(IServiceCollection services)
6970
config.SerializerName = "msg";
7071
})
7172
.WithMessagePack("msg");
73+
74+
// use etcd cache
75+
option.UseEtcd(options =>
76+
{
77+
options.Address = "http://121.196.220.148:12379";
78+
options.Timeout = 30000;
79+
options.SerializerName = "json";
80+
}, "e1").WithJson(jsonSerializerSettingsConfigure: x =>
81+
{
82+
x.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
83+
x.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
84+
}, "json");
7285
});
7386
}
7487

src/EasyCaching.Etcd/Configurations/EtcdCachingOptionsExtensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
22
using EasyCaching.Core;
33
using EasyCaching.Core.Configurations;
4+
using EasyCaching.Core.DistributedLock;
45
using EasyCaching.Etcd;
6+
using EasyCaching.Etcd.DistributedLock;
57
using Microsoft.Extensions.Configuration;
68
// ReSharper disable CheckNamespace
79

@@ -62,4 +64,15 @@ void Configure(EtcdCachingOptions x)
6264
options.RegisterExtension(new EtcdOptionsExtension(name, Configure));
6365
return options;
6466
}
67+
68+
/// <summary>
69+
/// Uses the Etcd lock.
70+
/// </summary>
71+
/// <param name="options">Options.</param>
72+
public static EasyCachingOptions UseEtcdLock(this EasyCachingOptions options)
73+
{
74+
options.UseDistributedLock<EtcdLockFactory>();
75+
76+
return options;
77+
}
6578
}

src/EasyCaching.Etcd/DefaultEtcdCachingProvider.Async.cs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace EasyCaching.Etcd
1010
{
1111

1212
/// <summary>
13-
/// MemoryCaching provider.
13+
/// EtcdCaching provider.
1414
/// </summary>
1515
public partial class DefaultEtcdCachingProvider : EasyCachingAbstractProvider
1616
{
@@ -28,7 +28,7 @@ public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<
2828
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
2929
ArgumentCheck.NotNegativeOrZero(expiration, nameof(expiration));
3030

31-
var result = await _cache.GetAsync<T>(cacheKey);
31+
var result = await _etcdClient.GetAsync<T>(cacheKey);
3232
if (result.HasValue)
3333
{
3434
if (_options.EnableLogging)
@@ -44,7 +44,7 @@ public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<
4444
if (_options.EnableLogging)
4545
_logger?.LogInformation($"Cache Missed : cachekey = {cacheKey}");
4646

47-
if (!await _cache.SetAsync($"{cacheKey}_Lock", "1", TimeSpan.FromMilliseconds(_options.LockMs)))
47+
if (!await _etcdClient.SetAsync($"{cacheKey}_Lock", "1", TimeSpan.FromMilliseconds(_options.LockMs)))
4848
{
4949
//wait for some ms
5050
await Task.Delay(_options.SleepMs, cancellationToken);
@@ -59,21 +59,21 @@ public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Func<
5959
{
6060
await SetAsync(cacheKey, res, expiration);
6161
//remove mutex key
62-
await _cache.DeleteAsync($"{cacheKey}_Lock");
62+
await _etcdClient.DeleteAsync($"{cacheKey}_Lock");
6363

6464
return new CacheValue<T>(res, true);
6565
}
6666
else
6767
{
6868
//remove mutex key
69-
await _cache.DeleteAsync($"{cacheKey}_Lock");
69+
await _etcdClient.DeleteAsync($"{cacheKey}_Lock");
7070
return CacheValue<T>.NoValue;
7171
}
7272
}
7373
catch
7474
{
7575
//remove mutex key
76-
await _cache.DeleteAsync($"{cacheKey}_Lock");
76+
await _etcdClient.DeleteAsync($"{cacheKey}_Lock");
7777
throw;
7878
}
7979
}
@@ -89,7 +89,7 @@ public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Cance
8989
{
9090
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
9191

92-
var result = await _cache.GetAsync<T>(cacheKey);
92+
var result = await _etcdClient.GetAsync<T>(cacheKey);
9393

9494
if (result.HasValue)
9595
{
@@ -119,7 +119,7 @@ public override async Task<CacheValue<T>> BaseGetAsync<T>(string cacheKey, Cance
119119
/// <param name="cancellationToken">CancellationToken</param>
120120
public override async Task<int> BaseGetCountAsync(string prefix = "", CancellationToken cancellationToken = default)
121121
{
122-
var dicData = await _cache.GetAllAsync(prefix);
122+
var dicData = await _etcdClient.GetAllAsync(prefix);
123123
return dicData != null ? dicData.Count : 0;
124124
}
125125

@@ -134,7 +134,7 @@ public override async Task<object> BaseGetAsync(string cacheKey, Type type, Canc
134134
{
135135
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
136136

137-
var result = await _cache.GetAsync<object>(cacheKey);
137+
var result = await _etcdClient.GetAsync<object>(cacheKey);
138138

139139
if (result != null)
140140
{
@@ -166,7 +166,7 @@ public override async Task BaseRemoveAsync(string cacheKey, CancellationToken ca
166166
{
167167
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
168168

169-
await _cache.DeleteAsync(cacheKey);
169+
await _etcdClient.DeleteAsync(cacheKey);
170170
}
171171

172172
/// <summary>
@@ -192,7 +192,7 @@ public override async Task BaseSetAsync<T>(string cacheKey, T cacheValue, TimeSp
192192

193193
//var valExpiration = expiration.Seconds <= 1 ? expiration : TimeSpan.FromSeconds(expiration.Seconds / 2);
194194
//var val = new CacheValue<T>(cacheValue, true, valExpiration);
195-
await _cache.SetAsync<T>(cacheKey, cacheValue, expiration);
195+
await _etcdClient.SetAsync<T>(cacheKey, cacheValue, expiration);
196196
}
197197

198198
/// <summary>
@@ -205,7 +205,7 @@ public override async Task<bool> BaseExistsAsync(string cacheKey, CancellationTo
205205
{
206206
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
207207

208-
return await _cache.ExistsAsync(cacheKey);
208+
return await _etcdClient.ExistsAsync(cacheKey);
209209
}
210210

211211
/// <summary>
@@ -218,7 +218,7 @@ public override async Task BaseRemoveByPrefixAsync(string prefix, CancellationTo
218218
{
219219
ArgumentCheck.NotNullOrWhiteSpace(prefix, nameof(prefix));
220220

221-
var count = await _cache.DeleteRangeDataAsync(prefix);
221+
var count = await _etcdClient.DeleteRangeDataAsync(prefix);
222222

223223
if (_options.EnableLogging)
224224
_logger?.LogInformation($"RemoveByPrefixAsync : prefix = {prefix} , count = {count}");
@@ -252,7 +252,7 @@ public override async Task BaseSetAllAsync<T>(IDictionary<string, T> values, Tim
252252

253253
foreach (var item in values)
254254
{
255-
await _cache.SetAsync(item.Key, item.Value, expiration);
255+
await _etcdClient.SetAsync(item.Key, item.Value, expiration);
256256
}
257257
}
258258

@@ -290,7 +290,7 @@ public override async Task<IEnumerable<string>> BaseGetAllKeysByPrefixAsync(stri
290290
if (_options.EnableLogging)
291291
_logger?.LogInformation("GetAllKeysAsync");
292292

293-
var dicData = await _cache.GetAllAsync(prefix);
293+
var dicData = await _etcdClient.GetAllAsync(prefix);
294294
List<string> result = new List<string>();
295295
foreach (var item in dicData)
296296
{
@@ -313,7 +313,7 @@ public override async Task<IDictionary<string, CacheValue<T>>> BaseGetByPrefixAs
313313
if (_options.EnableLogging)
314314
_logger?.LogInformation($"GetByPrefixAsync : prefix = {prefix}");
315315

316-
var dicData = await _cache.GetAllAsync(prefix);
316+
var dicData = await _etcdClient.GetAllAsync(prefix);
317317
Dictionary<string, CacheValue<T>> result = new Dictionary<string, CacheValue<T>>();
318318
foreach (var item in dicData)
319319
{
@@ -337,7 +337,7 @@ public override async Task BaseRemoveAllAsync(IEnumerable<string> cacheKeys, Can
337337

338338
foreach (var item in cacheKeys)
339339
{
340-
await _cache.DeleteAsync(item);
340+
await _etcdClient.DeleteAsync(item);
341341
}
342342
}
343343

@@ -351,7 +351,7 @@ public override async Task BaseFlushAsync(CancellationToken cancellationToken =
351351
if (_options.EnableLogging)
352352
_logger?.LogInformation("FlushAsync");
353353

354-
var dicData = await _cache.GetAllAsync("");
354+
var dicData = await _etcdClient.GetAllAsync("");
355355
if (dicData != null)
356356
{
357357
List<string> listKeys = new List<string>(dicData.Count);
@@ -361,7 +361,6 @@ public override async Task BaseFlushAsync(CancellationToken cancellationToken =
361361
}
362362
await BaseRemoveAllAsync(listKeys);
363363
}
364-
//throw new NotSupportedException("BaseFlushAsync is not supported in Etcd provider.");
365364
}
366365

367366
/// <summary>
@@ -379,8 +378,7 @@ public override async Task<bool> BaseTrySetAsync<T>(string cacheKey, T cacheValu
379378
ArgumentCheck.NotNull(cacheValue, nameof(cacheValue), _options.CacheNulls);
380379
ArgumentCheck.NotNegativeOrZero(expiration, nameof(expiration));
381380

382-
//var val = new CacheValue<T>(cacheValue, true, expiration);
383-
return await _cache.SetAsync(cacheKey, cacheValue, expiration);
381+
return await _etcdClient.SetAsync(cacheKey, cacheValue, expiration);
384382
}
385383

386384
/// <summary>
@@ -389,11 +387,11 @@ public override async Task<bool> BaseTrySetAsync<T>(string cacheKey, T cacheValu
389387
/// <param name="cacheKey">cache key</param>
390388
/// <param name="cancellationToken">CancellationToken</param>
391389
/// <returns>expiration</returns>
392-
public override Task<TimeSpan> BaseGetExpirationAsync(string cacheKey, CancellationToken cancellationToken = default)
390+
public override async Task<TimeSpan> BaseGetExpirationAsync(string cacheKey, CancellationToken cancellationToken = default)
393391
{
394392
ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
395-
396-
throw new NotSupportedException("BaseGetExpirationAsync is not supported in Etcd provider.");
393+
var secondsTTL = await _etcdClient.GetExpireTTLAsync(cacheKey);
394+
return TimeSpan.FromSeconds(secondsTTL);
397395
}
398396
}
399397
}

0 commit comments

Comments
 (0)