forked from ddrilling/AsbCloudServer
throttle CacheTable refresh
This commit is contained in:
parent
f881a2eb55
commit
fccfd538fc
@ -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();
|
||||||
cached.AddRange(entities);
|
Trace.WriteLine($"CacheTable<{typeof(TEntity).Name}> refresh");
|
||||||
data.refreshDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task InternalRefreshAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
cached.Clear();
|
|
||||||
var entities = await context.Set<TEntity>().AsNoTracking()
|
|
||||||
.ToListAsync(token).ConfigureAwait(false);
|
|
||||||
cached.AddRange(entities);
|
cached.AddRange(entities);
|
||||||
data.refreshDate = DateTime.Now;
|
data.refreshDate = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Refresh()
|
private async Task InternalRefreshAsync(bool force, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
if (!force && (data.refreshDate + minPeriodRefresh >= DateTime.Now))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cached.Clear();
|
||||||
|
var entities = await context.Set<TEntity>().AsNoTracking()
|
||||||
|
.ToListAsync(token).ConfigureAwait(false);
|
||||||
|
Trace.WriteLine($"CacheTable<{typeof(TEntity).Name}> refresh");
|
||||||
|
cached.AddRange(entities);
|
||||||
|
data.refreshDate = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user