Fix perf with cache

This commit is contained in:
2025-10-10 03:42:57 +07:00
parent bdda24cb60
commit b6b11be33a
13 changed files with 1646 additions and 32 deletions

View File

@@ -1,5 +1,6 @@
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Domain.Accounts;
using Managing.Domain.Users;
using Managing.Infrastructure.Databases.PostgreSql.Entities;
using Microsoft.EntityFrameworkCore;
@@ -66,12 +67,12 @@ public class PostgreSqlUserRepository : BaseRepositoryWithLogging, IUserReposito
}, nameof(GetUserByAgentNameAsync), ("agentName", agentName));
}
public async Task<User> GetUserByNameAsync(string name)
public async Task<User> GetUserByNameAsync(string name, bool fetchAccounts = false)
{
return await ExecuteWithLoggingAsync(async () =>
{
// Check cache first for frequently accessed users
var cacheKey = $"user_name_{name}";
var cacheKey = fetchAccounts ? $"user_name_with_accounts_{name}" : $"user_name_{name}";
var cachedUser = _cacheService.GetValue<User>(cacheKey);
if (cachedUser != null)
{
@@ -82,28 +83,61 @@ public class PostgreSqlUserRepository : BaseRepositoryWithLogging, IUserReposito
{
await PostgreSqlConnectionHelper.EnsureConnectionOpenAsync(_context);
// Optimized query with explicit SELECT to avoid loading unnecessary data
var userEntity = await _context.Users
.AsNoTracking()
.Where(u => u.Name == name)
.Select(u => new UserEntity
User user;
if (fetchAccounts)
{
// Fetch user with accounts in a single query
var userEntity = await _context.Users
.AsNoTracking()
.Include(u => u.Accounts)
.Where(u => u.Name == name)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
if (userEntity == null)
throw new InvalidOperationException($"User with name '{name}' not found");
user = PostgreSqlMappers.Map(userEntity);
// Map accounts using the existing mapper
if (userEntity.Accounts != null)
{
Id = u.Id,
Name = u.Name,
AgentName = u.AgentName,
AvatarUrl = u.AvatarUrl,
TelegramChannel = u.TelegramChannel
})
.FirstOrDefaultAsync()
.ConfigureAwait(false);
user.Accounts = userEntity.Accounts.Select(PostgreSqlMappers.Map).ToList();
}
else
{
user.Accounts = new List<Account>();
}
}
else
{
// Optimized query with explicit SELECT to avoid loading unnecessary data
var userEntity = await _context.Users
.AsNoTracking()
.Where(u => u.Name == name)
.Select(u => new UserEntity
{
Id = u.Id,
Name = u.Name,
AgentName = u.AgentName,
AvatarUrl = u.AvatarUrl,
TelegramChannel = u.TelegramChannel
})
.FirstOrDefaultAsync()
.ConfigureAwait(false);
if (userEntity == null)
throw new InvalidOperationException($"User with name '{name}' not found");
if (userEntity == null)
throw new InvalidOperationException($"User with name '{name}' not found");
var user = PostgreSqlMappers.Map(userEntity);
user = PostgreSqlMappers.Map(userEntity);
user.Accounts = new List<Account>(); // Initialize empty list
}
// Cache user for 5 minutes since user data doesn't change frequently
_cacheService.SaveValue(cacheKey, user, TimeSpan.FromMinutes(5));
// Use shorter cache time when including accounts since accounts change more frequently
var cacheTime = fetchAccounts ? TimeSpan.FromMinutes(2) : TimeSpan.FromMinutes(5);
_cacheService.SaveValue(cacheKey, user, cacheTime);
return user;
}
@@ -111,7 +145,7 @@ public class PostgreSqlUserRepository : BaseRepositoryWithLogging, IUserReposito
{
await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
}
}, nameof(GetUserByNameAsync), ("name", name));
}, nameof(GetUserByNameAsync), ("name", name), ("fetchAccounts", fetchAccounts));
}
public async Task<IEnumerable<User>> GetAllUsersAsync()
@@ -214,7 +248,9 @@ public class PostgreSqlUserRepository : BaseRepositoryWithLogging, IUserReposito
// Invalidate cache for updated user - handle both old and new AgentName
var nameCacheKey = $"user_name_{user.Name}";
var nameWithAccountsCacheKey = $"user_name_with_accounts_{user.Name}";
_cacheService.RemoveValue(nameCacheKey);
_cacheService.RemoveValue(nameWithAccountsCacheKey);
// Invalidate old AgentName cache if it existed
if (!string.IsNullOrEmpty(oldAgentName))