added a smart queue manager and moved proxy logic to proxy manager to make handler just schedule a call to it
This commit is contained in:
parent
da1c52a841
commit
e7c0fe2798
19 changed files with 903 additions and 231 deletions
167
libs/services/queue/src/service-cache.ts
Normal file
167
libs/services/queue/src/service-cache.ts
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
import { createCache, type CacheProvider, type CacheStats } from '@stock-bot/cache';
|
||||
import type { RedisConfig } from './types';
|
||||
import { getServiceConfig, type ServiceConfig } from './service-registry';
|
||||
|
||||
/**
|
||||
* Service-aware cache that uses the service's Redis DB
|
||||
* Automatically prefixes keys with the service's cache namespace
|
||||
*/
|
||||
export class ServiceCache implements CacheProvider {
|
||||
private cache: CacheProvider;
|
||||
private prefix: string;
|
||||
|
||||
constructor(
|
||||
serviceName: string,
|
||||
redisConfig: RedisConfig,
|
||||
isGlobalCache: boolean = false
|
||||
) {
|
||||
// Get service configuration
|
||||
const serviceConfig = getServiceConfig(serviceName);
|
||||
if (!serviceConfig && !isGlobalCache) {
|
||||
throw new Error(`Unknown service: ${serviceName}`);
|
||||
}
|
||||
|
||||
// Determine Redis DB and prefix
|
||||
let db: number;
|
||||
let prefix: string;
|
||||
|
||||
if (isGlobalCache) {
|
||||
// Global cache uses db:0
|
||||
db = 0;
|
||||
prefix = 'stock-bot:shared';
|
||||
} else {
|
||||
// Service cache uses service's DB
|
||||
db = serviceConfig!.db;
|
||||
prefix = serviceConfig!.cachePrefix;
|
||||
}
|
||||
|
||||
// Create underlying cache with correct DB
|
||||
const cacheConfig = {
|
||||
redisConfig: {
|
||||
...redisConfig,
|
||||
db,
|
||||
},
|
||||
keyPrefix: prefix + ':',
|
||||
};
|
||||
|
||||
this.cache = createCache(cacheConfig);
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
// Implement CacheProvider interface
|
||||
async get<T = any>(key: string): Promise<T | null> {
|
||||
return this.cache.get<T>(key);
|
||||
}
|
||||
|
||||
async set<T = any>(
|
||||
key: string,
|
||||
value: T,
|
||||
options?:
|
||||
| number
|
||||
| {
|
||||
ttl?: number;
|
||||
preserveTTL?: boolean;
|
||||
onlyIfExists?: boolean;
|
||||
onlyIfNotExists?: boolean;
|
||||
getOldValue?: boolean;
|
||||
}
|
||||
): Promise<T | null> {
|
||||
return this.cache.set(key, value, options);
|
||||
}
|
||||
|
||||
async del(key: string): Promise<void> {
|
||||
return this.cache.del(key);
|
||||
}
|
||||
|
||||
async exists(key: string): Promise<boolean> {
|
||||
return this.cache.exists(key);
|
||||
}
|
||||
|
||||
async clear(): Promise<void> {
|
||||
return this.cache.clear();
|
||||
}
|
||||
|
||||
async keys(pattern: string): Promise<string[]> {
|
||||
return this.cache.keys(pattern);
|
||||
}
|
||||
|
||||
getStats(): CacheStats {
|
||||
return this.cache.getStats();
|
||||
}
|
||||
|
||||
async health(): Promise<boolean> {
|
||||
return this.cache.health();
|
||||
}
|
||||
|
||||
async waitForReady(timeout?: number): Promise<void> {
|
||||
return this.cache.waitForReady(timeout);
|
||||
}
|
||||
|
||||
isReady(): boolean {
|
||||
return this.cache.isReady();
|
||||
}
|
||||
|
||||
// Enhanced cache methods (delegate to underlying cache if available)
|
||||
async update<T = any>(key: string, value: T): Promise<T | null> {
|
||||
if (this.cache.update) {
|
||||
return this.cache.update(key, value);
|
||||
}
|
||||
// Fallback implementation
|
||||
return this.cache.set(key, value, { preserveTTL: true });
|
||||
}
|
||||
|
||||
async setIfExists<T = any>(key: string, value: T, ttl?: number): Promise<boolean> {
|
||||
if (this.cache.setIfExists) {
|
||||
return this.cache.setIfExists(key, value, ttl);
|
||||
}
|
||||
// Fallback implementation
|
||||
const result = await this.cache.set(key, value, { onlyIfExists: true, ttl });
|
||||
return result !== null;
|
||||
}
|
||||
|
||||
async setIfNotExists<T = any>(key: string, value: T, ttl?: number): Promise<boolean> {
|
||||
if (this.cache.setIfNotExists) {
|
||||
return this.cache.setIfNotExists(key, value, ttl);
|
||||
}
|
||||
// Fallback implementation
|
||||
const result = await this.cache.set(key, value, { onlyIfNotExists: true, ttl });
|
||||
return result !== null;
|
||||
}
|
||||
|
||||
async replace<T = any>(key: string, value: T, ttl?: number): Promise<T | null> {
|
||||
if (this.cache.replace) {
|
||||
return this.cache.replace(key, value, ttl);
|
||||
}
|
||||
// Fallback implementation
|
||||
return this.cache.set(key, value, ttl);
|
||||
}
|
||||
|
||||
async updateField<T = any>(key: string, updater: (current: T | null) => T, ttl?: number): Promise<T | null> {
|
||||
if (this.cache.updateField) {
|
||||
return this.cache.updateField(key, updater, ttl);
|
||||
}
|
||||
// Fallback implementation
|
||||
const current = await this.cache.get<T>(key);
|
||||
const updated = updater(current);
|
||||
return this.cache.set(key, updated, ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actual Redis key with prefix
|
||||
*/
|
||||
getKey(key: string): string {
|
||||
return `${this.prefix}:${key}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory function to create service cache
|
||||
*/
|
||||
export function createServiceCache(
|
||||
serviceName: string,
|
||||
redisConfig: RedisConfig,
|
||||
options: { global?: boolean } = {}
|
||||
): ServiceCache {
|
||||
return new ServiceCache(serviceName, redisConfig, options.global);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue