feat(cache): implement Redis caching layer for hot-read endpoints
Add cache-aside pattern for listing detail, search results, market analytics (4 endpoints), and user profile queries. Cache invalidation on all write mutations. Prometheus cache_hit_total/cache_miss_total metrics with resource labels. - CacheService: getOrSet, invalidate, invalidateByPrefix (SCAN-based) - TTLs: listing 5m, search 1m, market 30m, profile 10m - All 230 tests passing (13 new cache tests + 6 updated handler tests) Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { type IQueryHandler, QueryHandler } from '@nestjs/cqrs';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { CacheService, CachePrefix, CacheTTL } from '@modules/shared/infrastructure/cache.service';
|
||||
import { SearchPropertiesQuery } from './search-properties.query';
|
||||
import {
|
||||
SEARCH_REPOSITORY,
|
||||
@@ -11,6 +12,7 @@ import {
|
||||
export class SearchPropertiesHandler implements IQueryHandler<SearchPropertiesQuery> {
|
||||
constructor(
|
||||
@Inject(SEARCH_REPOSITORY) private readonly searchRepo: ISearchRepository,
|
||||
private readonly cache: CacheService,
|
||||
) {}
|
||||
|
||||
async execute(query: SearchPropertiesQuery): Promise<SearchResult> {
|
||||
@@ -46,12 +48,36 @@ export class SearchPropertiesHandler implements IQueryHandler<SearchPropertiesQu
|
||||
filters.push(`city:=${query.city}`);
|
||||
}
|
||||
|
||||
return this.searchRepo.search({
|
||||
const searchParams = {
|
||||
query: query.query,
|
||||
filterBy: filters.join(' && '),
|
||||
sortBy: query.sortBy,
|
||||
page: query.page,
|
||||
perPage: query.perPage,
|
||||
});
|
||||
};
|
||||
|
||||
const cacheKey = CacheService.buildKey(
|
||||
CachePrefix.SEARCH,
|
||||
query.query ?? '*',
|
||||
query.propertyType,
|
||||
query.transactionType,
|
||||
query.district,
|
||||
query.city,
|
||||
query.page,
|
||||
query.perPage,
|
||||
query.priceMin,
|
||||
query.priceMax,
|
||||
query.areaMin,
|
||||
query.areaMax,
|
||||
query.bedrooms,
|
||||
query.sortBy,
|
||||
);
|
||||
|
||||
return this.cache.getOrSet(
|
||||
cacheKey,
|
||||
() => this.searchRepo.search(searchParams),
|
||||
CacheTTL.SEARCH_RESULTS,
|
||||
'search',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user