Basic redis object cache implementation
This commit is contained in:
parent
a0425aaf4c
commit
3e4410f52c
2 changed files with 48 additions and 4 deletions
|
@ -0,0 +1,38 @@
|
||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
|
||||||
|
namespace Iceshrimp.Backend.Core.Extensions;
|
||||||
|
|
||||||
|
public static class DistributedCacheExtensions {
|
||||||
|
//TODO: named caches, CacheService?
|
||||||
|
//TODO: thread-safe locks to prevent fetching data more than once
|
||||||
|
|
||||||
|
public static async Task<T?> Get<T>(this IDistributedCache cache, string key) {
|
||||||
|
var buffer = await cache.GetAsync(key);
|
||||||
|
if (buffer == null) return default;
|
||||||
|
|
||||||
|
var stream = new MemoryStream(buffer);
|
||||||
|
var data = await JsonSerializer.DeserializeAsync<T>(stream);
|
||||||
|
|
||||||
|
return data != null ? (T)data : default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<T> Fetch<T>(this IDistributedCache cache, string key, TimeSpan ttl,
|
||||||
|
Func<Task<T>> fetcher) {
|
||||||
|
var hit = await cache.Get<T>(key);
|
||||||
|
if (hit != null) return hit;
|
||||||
|
|
||||||
|
var fetched = await fetcher();
|
||||||
|
await cache.Set(key, fetched, ttl);
|
||||||
|
return fetched;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task Set<T>(this IDistributedCache cache, string key, T data, TimeSpan ttl) {
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
await JsonSerializer.SerializeAsync(ms, data);
|
||||||
|
var buffer = new Memory<byte>();
|
||||||
|
_ = await ms.ReadAsync(buffer);
|
||||||
|
var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = ttl };
|
||||||
|
await cache.SetAsync(key, buffer.ToArray(), options);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ using Iceshrimp.Backend.Core.Federation.ActivityPub;
|
||||||
using Iceshrimp.Backend.Core.Helpers;
|
using Iceshrimp.Backend.Core.Helpers;
|
||||||
using Iceshrimp.Backend.Core.Middleware;
|
using Iceshrimp.Backend.Core.Middleware;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Iceshrimp.Backend.Core.Services;
|
namespace Iceshrimp.Backend.Core.Services;
|
||||||
|
@ -19,7 +20,9 @@ public class UserService(
|
||||||
IOptions<Config.InstanceSection> instance,
|
IOptions<Config.InstanceSection> instance,
|
||||||
ILogger<UserService> logger,
|
ILogger<UserService> logger,
|
||||||
DatabaseContext db,
|
DatabaseContext db,
|
||||||
ActivityFetcherService fetchSvc) {
|
ActivityFetcherService fetchSvc,
|
||||||
|
IDistributedCache cache
|
||||||
|
) {
|
||||||
private (string Username, string? Host) AcctToTuple(string acct) {
|
private (string Username, string? Host) AcctToTuple(string acct) {
|
||||||
if (!acct.StartsWith("acct:")) throw new GracefulException(HttpStatusCode.BadRequest, "Invalid query");
|
if (!acct.StartsWith("acct:")) throw new GracefulException(HttpStatusCode.BadRequest, "Invalid query");
|
||||||
|
|
||||||
|
@ -161,10 +164,13 @@ public class UserService(
|
||||||
return await GetOrCreateSystemUser("relay.actor");
|
return await GetOrCreateSystemUser("relay.actor");
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: cache in redis
|
|
||||||
private async Task<User> GetOrCreateSystemUser(string username) {
|
private async Task<User> GetOrCreateSystemUser(string username) {
|
||||||
return await db.Users.FirstOrDefaultAsync(p => p.UsernameLower == username && p.Host == null) ??
|
return await cache.Fetch($"systemUser:{username}", TimeSpan.FromHours(24), async () => {
|
||||||
await CreateSystemUser(username);
|
logger.LogTrace("GetOrCreateSystemUser delegate method called for user {username}", username);
|
||||||
|
return await db.Users.FirstOrDefaultAsync(p => p.UsernameLower == username &&
|
||||||
|
p.Host == null) ??
|
||||||
|
await CreateSystemUser(username);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<User> CreateSystemUser(string username) {
|
private async Task<User> CreateSystemUser(string username) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue