Как обрабатывать недействительность кэша в Redis при изменении предикатов запроса в системе страничного вывода

1
8

Я работаю над системой, в которой я кэширую постраничные результаты с помощью Redis. Логика кэширования хранит данные для текущей страницы, следующей страницы и страницы после нее. Ключ кэша каждой страницы основан на индексе страницы и хэше предиката запроса. Проблема возникает, когда предикат запроса изменяется. Мне нужно убедиться, что кэш отражает результаты нового предиката и что все старые записи кэша, связанные с предыдущим предикатом, аннулированы.

В частности, я реализовал систему кэширования, которая обрабатывает: Хранение данных для текущей страницы и следующих двух страниц. Генерацию ключей кэша на основе индекса страницы и хэша предиката запроса.

Ниже приведены мои codeы, которые помогут вам.

Чего я хочу добиться:

Когда новый запрос выполняется с другим предикатом, я хочу убедиться, что старые записи кэша аннулированы, а новые данные извлекаются из базы данных и кэшируются на основе нового предиката. Это включает в себя очистку кэша для страниц, связанных со старым предикатом, и сохранение новых страниц в соответствии с обновленным предикатом.

Что я пробовал: Я использовал хэш предиката для создания уникального ключа кэша. Однако я не уверен, как эффективно управлять аннулированием кэша при изменении предикатов, особенно как обрабатывать записи кэша для нескольких страниц, которые могут быть затронуты.

    public class GetDataPagedListQueryHandler : IRequestHandler<GetDataPagedListQueryRequest, OptResult<PaginatedList<GetDataPagedListQueryResponse>>>
    {
        private readonly IDepartmentService _departmentService;
        private readonly IMapper _mapper;

        public GetDataPagedListQueryHandler(IDepartmentService departmentService, IMapper mapper)
        {
            _departmentService = departmentService;
            _mapper = mapper;
        }

        public async Task<OptResult<PaginatedList<GetDataPagedListQueryResponse>>> Handle(GetDataPagedListQueryRequest request, CancellationToken cancellationToken)
        {
            return await ExceptionHandler.HandleOptResultAsync(async () =>
            {
                var model = _mapper.Map<GetAllPaged_Index_Dto>(request);

                var result = await _departmentService.GetDataPagedForDepartment(model);

                var response = _mapper.Map<PaginatedList<GetDataPagedListQueryResponse>>(result.Data);

                if (response != null) 
                    return await OptResult<PaginatedList<GetDataPagedListQueryResponse>>.SuccessAsync(response, Messages.Successfull);
                return await OptResult<PaginatedList<GetDataPagedListQueryResponse>>.FailureAsync(Messages.UnSuccessfull);
            });
        }
    }
}
[Service(ServiceLifetime.Scoped)]
    public class DepartmentService : IDepartmentService
    {
        private readonly IDepartmentReadRepository _readRepository;
        private readonly IDepartmentWriteRepository _writeRepository;
        private readonly DepartmentSpecifications _departmentSpecifications;
        private readonly IRedisCacheService _redisCacheService;

        public DepartmentService(IDepartmentReadRepository readRepository, IDepartmentWriteRepository writeRepository, DepartmentSpecifications departmentSpecifications, IRedisCacheService redisCacheService)
        {
            _readRepository = readRepository;
            _writeRepository = writeRepository;
            _departmentSpecifications = departmentSpecifications;
            _redisCacheService = redisCacheService;
        }
public async Task<OptResult<PaginatedList<Department>>> GetDataPagedForDepartment(GetAllPaged_Index_Dto model)
        {
            var predicate = _departmentSpecifications.GetDataPagedListPredicate(model);
            if (string.IsNullOrEmpty(model.OrderBy)) model.OrderBy = "DepartmentName ASC";

            PaginatedList<Department> pagedDepartments;

            if (!string.IsNullOrEmpty(model.SearchText) || !_redisCacheService.IsConnected)
                pagedDepartments = await _readRepository.GetDataPagedAsync(predicate, "", model.PageIndex, model.Take, model.OrderBy);
            else
                pagedDepartments = await _redisCacheService.GetPaginatedListAsync("departments", model.PageIndex, async pageIndex =>
                   await _readRepository.GetDataPagedAsync(predicate, "", pageIndex, model.Take, model.OrderBy));

            return await OptResult<PaginatedList<Department>>.SuccessAsync(pagedDepartments, Messages.Successfull);
        }
    }
}
public class RedisCacheService : IRedisCacheService
    {
        private readonly IDatabase _database;
        private readonly IConnectionMultiplexer _connectionMultiplexer;

        public RedisCacheService(IConnectionMultiplexer connectionMultiplexer)
        {
            _database = connectionMultiplexer.GetDatabase();
            _connectionMultiplexer = connectionMultiplexer;

        }
        public bool IsConnected => _connectionMultiplexer.IsConnected;
public async Task<PaginatedList<T>> GetPaginatedListAsync<T>(string cachePrefixName, int pageIndex, Func<int, Task<PaginatedList<T>>> data) where T : class
        {
            int minPageIndex = pageIndex;
            int maxPageIndex = pageIndex + 2;

            if (pageIndex >= 1)
            {
                int prevMaxPageIndex = minPageIndex - 1;
                int prevMinPageIndex = minPageIndex - 2;

                for (int i = prevMinPageIndex; i <= prevMaxPageIndex; i++)
                {
                    if (i >= 1)
                    {
                        string oldPageKey = $"{cachePrefixName}_{i}";
                        await DeleteAsync(oldPageKey);
                    }
                }
            }
            for (int i = minPageIndex; i <= maxPageIndex; i++)
            {
                string pageKey = $"{cachePrefixName}_{i}";
                var cachedData = await GetAsync<PaginatedList<T>>(pageKey);
                if (cachedData == null)
                {
                    var pageData = await data(i);
                    if (pageData.Data.Count > 0)
                    {
                        await SetAsync(pageKey, pageData, TimeSpan.FromHours(3));
                    }
                }
            }
            string currentPageKey = $"{cachePrefixName}_{pageIndex}";
            return await GetAsync<PaginatedList<T>>(currentPageKey);
        }
Всемил
Вопрос задан16 марта 2024 г.

1 Ответ

2
Боян
Ответ получен1 сентября 2024 г.

Ваш ответ

Загрузить файл.