MVP реализации MoexVibe — NestJS бэкенд + React фронтенд + CI/CD #1

Merged
ksv741 merged 21 commits from feat/mvp-implementation into main 2026-06-13 21:07:34 +03:00
2 changed files with 60 additions and 0 deletions
Showing only changes of commit 5315473973 - Show all commits

View File

@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { CacheModule as NestCacheModule } from '@nestjs/cache-manager';
import { CacheService } from './cache.service';
@Module({
imports: [
NestCacheModule.register({
ttl: 900,
max: 1000,
isGlobal: true,
}),
],
providers: [CacheService],
exports: [CacheService],
})
export class CacheModule {}

View File

@ -0,0 +1,44 @@
import { Injectable, Inject } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class CacheService {
constructor(
@Inject(CACHE_MANAGER) private cacheManager: Cache,
private configService: ConfigService,
) {}
async get<T>(key: string): Promise<T | undefined> {
return this.cacheManager.get<T>(key);
}
async set(key: string, value: unknown, ttl?: number): Promise<void> {
await this.cacheManager.set(key, value, ttl);
}
private buildKey(...parts: string[]): string {
return parts.join(':');
}
async getOrFetch<T>(
keyPrefix: string,
keyParts: string[],
fetchFn: () => Promise<T>,
ttlConfigKey: string,
): Promise<{ data: T; fromCache: boolean; cachedAt: string | null }> {
const key = this.buildKey(keyPrefix, ...keyParts);
const ttl = this.configService.get<number>(`app.cache.${ttlConfigKey}`, 900);
const cached = await this.get<T>(key);
if (cached !== undefined) {
return { data: cached, fromCache: true, cachedAt: null };
}
const data = await fetchFn();
await this.set(key, data, ttl);
return { data, fromCache: false, cachedAt: new Date().toISOString() };
}
}