Как правильно реализовать инвалидацию кэша при изменении данных?

Я реализовал очистку кэша через флаг очистки внутри сессии юзера, но мне кажется этот подход крайне неверен, и определенно имеет кучу недостатоков.

Было бы проще если ключ к кэшу был единым, но у меня ключ к кэшу строится на основе параметров сортировки, так что я не представляю как иначе.

public class FileController : ControllerBase
{
    private readonly IRepository<FileModel> _fileRepository;
    private readonly ISorting _sorting;
    private readonly IRedisCache _redisCache;
    private readonly IUserInfo _userInfo;

    public FileController(
        IRepository<FileModel> fileRepository,
        ISorting sorting,
        IRedisCache redisCache,
        IUserInfo userInfo)
    {
        _fileRepository = fileRepository;
        _sorting = sorting;
        _redisCache = redisCache;
        _userInfo = userInfo;
    }

    [HttpDelete("{fileId}")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteFileFromHistory([FromRoute] int fileId)
    {
        try
        {
            await _fileRepository.DeleteByFilter(query => query.Where(f => f.file_id.Equals(fileId) && f.user_id.Equals(_userInfo.UserId)));
            HttpContext.Session.SetString(Constants.CACHE_FILES, true.ToString());

            return StatusCode(200, new { message = SuccessMessage.SuccessFileDeleted });
        }
        catch (EntityNotDeletedException ex)
        {
            return StatusCode(500, new { message = ex.Message });
        }
    }

    [HttpGet("{fileId}")]
    public async Task<IActionResult> GetOneFile([FromRoute] int fileId)
    {
        var cacheKey = $"File_{fileId}";

        var cacheFile = JsonConvert.DeserializeObject<FileModel>(await _redisCache.GetCachedData(cacheKey));
        if (cacheFile is not null)
        {
            if (cacheFile.user_id != _userInfo.UserId)
                return StatusCode(404);

            return StatusCode(200, new { file = cacheFile });
        }

        var file = await _fileRepository.GetByFilter(query => query.Where(f => f.file_id.Equals(fileId) && f.user_id.Equals(_userInfo.UserId)));
        if (file is null)
            return StatusCode(404);

        await _redisCache.CacheData(cacheKey, file, TimeSpan.FromMinutes(5));

        return StatusCode(200, new { file });
    }

    [HttpGet("all")]
    public async Task<IActionResult> GetAllFiles([FromQuery] int skip, [FromQuery] int count,
        [FromQuery] bool byDesc, [FromQuery] string? type, [FromQuery] string? category, [FromQuery] string? mime)
    {
        var cacheKey = $"Files_{_userInfo.UserId}_{skip}_{count}_{byDesc}_{type}_{category}_{mime}";

        bool clearCache = bool.TryParse(HttpContext.Session.GetString(Constants.CACHE_FILES), out var parsedValue) ? parsedValue : true;
        if (clearCache)
        {
            await _redisCache.DeleteCache(cacheKey);
            HttpContext.Session.SetString(Constants.CACHE_FILES, false.ToString());
        }

        var cacheFiles = await _redisCache.GetCachedData(cacheKey);
        if (cacheFiles is not null)
            return StatusCode(200, new { files = JsonConvert.DeserializeObject<IEnumerable<FileModel>>(cacheFiles) });

        var files = await _fileRepository.GetAll(_sorting.SortFiles(_userInfo.UserId, skip, count, byDesc, type, mime, category));

        await _redisCache.CacheData(cacheKey, files, TimeSpan.FromMinutes(3));

        return StatusCode(200, new { files });
    }
}

Ответы (0 шт):