throttle CacheTable refresh

This commit is contained in:
Фролов 2021-11-10 17:01:18 +05:00
parent f881a2eb55
commit fccfd538fc

View File

@ -14,6 +14,8 @@ namespace AsbCloudInfrastructure.Services.Cache
{ {
private const int semaphoreTimeout = 5_000; private const int semaphoreTimeout = 5_000;
private static readonly SemaphoreSlim semaphore = new(1); private static readonly SemaphoreSlim semaphore = new(1);
private static readonly TimeSpan minPeriodRefresh = TimeSpan.FromSeconds(3);
private readonly DbContext context; private readonly DbContext context;
private (DateTime refreshDate, IEnumerable entities) data; private (DateTime refreshDate, IEnumerable entities) data;
private readonly List<TEntity> cached; private readonly List<TEntity> cached;
@ -26,7 +28,7 @@ namespace AsbCloudInfrastructure.Services.Cache
dbSet = context.Set<TEntity>(); dbSet = context.Set<TEntity>();
cached = (List<TEntity>)data.entities; cached = (List<TEntity>)data.entities;
if (cached.Count == 0) if (cached.Count == 0)
Refresh(); Refresh(false);
} }
public TEntity this[int index] { get => cached.ElementAt(index); } public TEntity this[int index] { get => cached.ElementAt(index); }
@ -89,37 +91,45 @@ namespace AsbCloudInfrastructure.Services.Cache
return true; return true;
} }
private void InternalRefresh() private void InternalRefresh(bool force)
{ {
if (!force && (data.refreshDate + minPeriodRefresh >= DateTime.Now))
return;
cached.Clear(); cached.Clear();
var entities = dbSet.AsNoTracking().ToList(); var entities = dbSet.AsNoTracking().ToList();
Trace.WriteLine($"CacheTable<{typeof(TEntity).Name}> refresh");
cached.AddRange(entities); cached.AddRange(entities);
data.refreshDate = DateTime.Now; data.refreshDate = DateTime.Now;
} }
private async Task InternalRefreshAsync(CancellationToken token = default) private async Task InternalRefreshAsync(bool force, CancellationToken token = default)
{ {
if (!force && (data.refreshDate + minPeriodRefresh >= DateTime.Now))
return;
cached.Clear(); cached.Clear();
var entities = await context.Set<TEntity>().AsNoTracking() var entities = await context.Set<TEntity>().AsNoTracking()
.ToListAsync(token).ConfigureAwait(false); .ToListAsync(token).ConfigureAwait(false);
Trace.WriteLine($"CacheTable<{typeof(TEntity).Name}> refresh");
cached.AddRange(entities); cached.AddRange(entities);
data.refreshDate = DateTime.Now; data.refreshDate = DateTime.Now;
} }
public int Refresh() public int Refresh(bool force)
{ {
Sync((wasFree) => { Sync((wasFree) => {
if (wasFree) if (wasFree)
InternalRefresh(); InternalRefresh(force);
}); });
return cached.Count; return cached.Count;
} }
public async Task<int> RefreshAsync(CancellationToken token = default) public async Task<int> RefreshAsync(bool force, CancellationToken token = default)
{ {
await SyncAsync(async (wasFree, token) => { await SyncAsync(async (wasFree, token) => {
if (wasFree) if (wasFree)
await InternalRefreshAsync(token).ConfigureAwait(false); await InternalRefreshAsync(force, token).ConfigureAwait(false);
}, token).ConfigureAwait(false); }, token).ConfigureAwait(false);
return cached.Count; return cached.Count;
} }
@ -138,14 +148,14 @@ namespace AsbCloudInfrastructure.Services.Cache
if (result != default) if (result != default)
return; return;
InternalRefresh(); InternalRefresh(true);
result = cached.FirstOrDefault(predicate); result = cached.FirstOrDefault(predicate);
if (result != default) if (result != default)
return; return;
var entry = dbSet.Add(makeNew()); var entry = dbSet.Add(makeNew());
context.SaveChanges(); context.SaveChanges();
InternalRefresh(); InternalRefresh(true);
result = entry.Entity; result = entry.Entity;
}); });
return result; return result;
@ -157,7 +167,7 @@ namespace AsbCloudInfrastructure.Services.Cache
if (result != default) if (result != default)
return result; return result;
Refresh(); Refresh(false);
return cached.FirstOrDefault(); return cached.FirstOrDefault();
} }
@ -167,7 +177,7 @@ namespace AsbCloudInfrastructure.Services.Cache
if (result != default) if (result != default)
return result; return result;
await RefreshAsync(token); await RefreshAsync(false, token);
return cached.FirstOrDefault(); return cached.FirstOrDefault();
} }
@ -177,7 +187,7 @@ namespace AsbCloudInfrastructure.Services.Cache
if (result != default) if (result != default)
return result; return result;
Refresh(); Refresh(false);
return cached.FirstOrDefault(predicate); return cached.FirstOrDefault(predicate);
} }
@ -187,7 +197,7 @@ namespace AsbCloudInfrastructure.Services.Cache
if (result != default) if (result != default)
return result; return result;
await RefreshAsync(token); await RefreshAsync(false, token);
return cached.FirstOrDefault(predicate); return cached.FirstOrDefault(predicate);
} }
@ -199,7 +209,7 @@ namespace AsbCloudInfrastructure.Services.Cache
if (result.Any()) if (result.Any())
return result; return result;
Refresh(); Refresh(false);
result = (predicate != default) result = (predicate != default)
? cached.Where(predicate) ? cached.Where(predicate)
: cached; : cached;
@ -218,7 +228,7 @@ namespace AsbCloudInfrastructure.Services.Cache
if (result.Any()) if (result.Any())
return result; return result;
await RefreshAsync(token); await RefreshAsync(false, token);
result = (predicate != default) result = (predicate != default)
? cached.Where(predicate) ? cached.Where(predicate)
: cached; : cached;
@ -236,7 +246,7 @@ namespace AsbCloudInfrastructure.Services.Cache
else else
dbSet.Add(entity); dbSet.Add(entity);
context.SaveChanges(); context.SaveChanges();
InternalRefresh(); InternalRefresh(true);
}); });
} }
@ -247,7 +257,7 @@ namespace AsbCloudInfrastructure.Services.Cache
else else
dbSet.Add(entity); dbSet.Add(entity);
await context.SaveChangesAsync(token).ConfigureAwait(false); await context.SaveChangesAsync(token).ConfigureAwait(false);
await InternalRefreshAsync(token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
}, token); }, token);
public void Upsert(IEnumerable<TEntity> entities) public void Upsert(IEnumerable<TEntity> entities)
@ -265,7 +275,7 @@ namespace AsbCloudInfrastructure.Services.Cache
dbSet.Add(entity); dbSet.Add(entity);
} }
context.SaveChanges(); context.SaveChanges();
InternalRefresh(); InternalRefresh(true);
}); });
} }
@ -284,7 +294,7 @@ namespace AsbCloudInfrastructure.Services.Cache
dbSet.Add(entity); dbSet.Add(entity);
} }
await context.SaveChangesAsync(token).ConfigureAwait(false); await context.SaveChangesAsync(token).ConfigureAwait(false);
await InternalRefreshAsync(token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
}, token); }, token);
} }
@ -293,14 +303,14 @@ namespace AsbCloudInfrastructure.Services.Cache
{ {
dbSet.RemoveRange(dbSet.Where(predicate)); dbSet.RemoveRange(dbSet.Where(predicate));
context.SaveChanges(); context.SaveChanges();
InternalRefresh(); InternalRefresh(true);
}); });
public Task RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default) public Task RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
=> SyncAsync(async (wasFree, token) => { => SyncAsync(async (wasFree, token) => {
dbSet.RemoveRange(dbSet.Where(predicate)); dbSet.RemoveRange(dbSet.Where(predicate));
await context.SaveChangesAsync(token).ConfigureAwait(false); await context.SaveChangesAsync(token).ConfigureAwait(false);
await InternalRefreshAsync(token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
}, token); }, token);
public TEntity Insert(TEntity entity) public TEntity Insert(TEntity entity)
@ -310,7 +320,7 @@ namespace AsbCloudInfrastructure.Services.Cache
{ {
var entry = dbSet.Add(entity); var entry = dbSet.Add(entity);
context.SaveChanges(); context.SaveChanges();
InternalRefresh(); InternalRefresh(true);
result = entry.Entity; result = entry.Entity;
}); });
return result; return result;
@ -323,7 +333,7 @@ namespace AsbCloudInfrastructure.Services.Cache
{ {
var entry = dbSet.Add(entity); var entry = dbSet.Add(entity);
await context.SaveChangesAsync(token).ConfigureAwait(false); await context.SaveChangesAsync(token).ConfigureAwait(false);
await InternalRefreshAsync(token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
result = entry.Entity; result = entry.Entity;
}, token); }, token);
return result; return result;
@ -335,7 +345,7 @@ namespace AsbCloudInfrastructure.Services.Cache
Sync(_ => { Sync(_ => {
dbSet.AddRange(newEntities); dbSet.AddRange(newEntities);
result = context.SaveChanges(); result = context.SaveChanges();
InternalRefresh(); InternalRefresh(true);
}); });
return result; return result;
} }
@ -346,7 +356,7 @@ namespace AsbCloudInfrastructure.Services.Cache
await SyncAsync(async (wasFree, token) => { await SyncAsync(async (wasFree, token) => {
dbSet.AddRange(newEntities); dbSet.AddRange(newEntities);
result = await context.SaveChangesAsync(token).ConfigureAwait(false); result = await context.SaveChangesAsync(token).ConfigureAwait(false);
await RefreshAsync(token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
}, token); }, token);
return result; return result;
} }