removed configs from all libs and will inject them within the services themselves

This commit is contained in:
Boki 2025-06-18 14:50:47 -04:00
parent fd28162811
commit 6cc5b339bc
32 changed files with 366 additions and 349 deletions

View file

@ -11,7 +11,6 @@
"test": "bun test"
},
"dependencies": {
"@stock-bot/config": "*",
"@stock-bot/logger": "*",
"ioredis": "^5.3.2"
},

View file

@ -1,11 +1,12 @@
import Redis from 'ioredis';
import { dragonflyConfig } from '@stock-bot/config';
import { getLogger } from '@stock-bot/logger';
import type { RedisConfig } from './types';
interface ConnectionConfig {
name: string;
singleton?: boolean;
db?: number;
redisConfig: RedisConfig;
}
/**
@ -32,12 +33,12 @@ export class RedisConnectionManager {
* @returns Redis connection instance
*/
getConnection(config: ConnectionConfig): Redis {
const { name, singleton = false, db } = config;
const { name, singleton = false, db, redisConfig } = config;
if (singleton) {
// Use shared connection across all instances
if (!RedisConnectionManager.sharedConnections.has(name)) {
const connection = this.createConnection(name, db);
const connection = this.createConnection(name, redisConfig, db);
RedisConnectionManager.sharedConnections.set(name, connection);
this.logger.info(`Created shared Redis connection: ${name}`);
}
@ -45,7 +46,7 @@ export class RedisConnectionManager {
} else {
// Create unique connection per instance
const uniqueName = `${name}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const connection = this.createConnection(uniqueName, db);
const connection = this.createConnection(uniqueName, redisConfig, db);
this.connections.set(uniqueName, connection);
this.logger.info(`Created unique Redis connection: ${uniqueName}`);
return connection;
@ -55,33 +56,31 @@ export class RedisConnectionManager {
/**
* Create a new Redis connection with configuration
*/
private createConnection(name: string, db?: number): Redis {
const redisConfig = {
host: dragonflyConfig.DRAGONFLY_HOST,
port: dragonflyConfig.DRAGONFLY_PORT,
password: dragonflyConfig.DRAGONFLY_PASSWORD || undefined,
username: dragonflyConfig.DRAGONFLY_USERNAME || undefined,
db: db ?? dragonflyConfig.DRAGONFLY_DATABASE,
maxRetriesPerRequest: dragonflyConfig.DRAGONFLY_MAX_RETRIES,
retryDelayOnFailover: dragonflyConfig.DRAGONFLY_RETRY_DELAY,
connectTimeout: dragonflyConfig.DRAGONFLY_CONNECT_TIMEOUT,
commandTimeout: dragonflyConfig.DRAGONFLY_COMMAND_TIMEOUT,
keepAlive: dragonflyConfig.DRAGONFLY_ENABLE_KEEPALIVE
? dragonflyConfig.DRAGONFLY_KEEPALIVE_INTERVAL * 1000
: 0,
private createConnection(name: string, config: RedisConfig, db?: number): Redis {
const redisOptions = {
host: config.host,
port: config.port,
password: config.password || undefined,
username: config.username || undefined,
db: db ?? config.db ?? 0,
maxRetriesPerRequest: config.maxRetriesPerRequest ?? 3,
retryDelayOnFailover: config.retryDelayOnFailover ?? 100,
connectTimeout: config.connectTimeout ?? 10000,
commandTimeout: config.commandTimeout ?? 5000,
keepAlive: config.keepAlive ?? 0,
connectionName: name,
lazyConnect: false, // Connect immediately instead of waiting for first command
...(dragonflyConfig.DRAGONFLY_TLS && {
...(config.tls && {
tls: {
cert: dragonflyConfig.DRAGONFLY_TLS_CERT_FILE || undefined,
key: dragonflyConfig.DRAGONFLY_TLS_KEY_FILE || undefined,
ca: dragonflyConfig.DRAGONFLY_TLS_CA_FILE || undefined,
rejectUnauthorized: !dragonflyConfig.DRAGONFLY_TLS_SKIP_VERIFY,
cert: config.tls.cert || undefined,
key: config.tls.key || undefined,
ca: config.tls.ca || undefined,
rejectUnauthorized: config.tls.rejectUnauthorized ?? true,
},
}),
};
const redis = new Redis(redisConfig);
const redis = new Redis(redisOptions);
// Setup event handlers
redis.on('connect', () => {

View file

@ -1,6 +1,6 @@
import { RedisConnectionManager } from './connection-manager';
import { RedisCache } from './redis-cache';
import type { CacheOptions, CacheProvider } from './types';
import type { CacheOptions, CacheProvider, RedisConfig } from './types';
// Cache instances registry to prevent multiple instances with same prefix
const cacheInstances = new Map<string, CacheProvider>();
@ -8,7 +8,7 @@ const cacheInstances = new Map<string, CacheProvider>();
/**
* Create a Redis cache instance with trading-optimized defaults
*/
export function createCache(options: Partial<CacheOptions> = {}): CacheProvider {
export function createCache(options: CacheOptions): CacheProvider {
const defaultOptions: CacheOptions = {
keyPrefix: 'cache:',
ttl: 3600, // 1 hour default
@ -37,39 +37,42 @@ export function createCache(options: Partial<CacheOptions> = {}): CacheProvider
/**
* Create a cache instance for trading data
*/
export function createTradingCache(options: Partial<CacheOptions> = {}): CacheProvider {
export function createTradingCache(redisConfig: RedisConfig, options?: Partial<Omit<CacheOptions, 'redisConfig'>>): CacheProvider {
return createCache({
keyPrefix: 'trading:',
ttl: 3600, // 1 hour default
enableMetrics: true,
shared: true,
...options,
redisConfig,
});
}
/**
* Create a cache for market data with shorter TTL
*/
export function createMarketDataCache(options: Partial<CacheOptions> = {}): CacheProvider {
export function createMarketDataCache(redisConfig: RedisConfig, options?: Partial<Omit<CacheOptions, 'redisConfig'>>): CacheProvider {
return createCache({
keyPrefix: 'market:',
ttl: 300, // 5 minutes for market data
enableMetrics: true,
shared: true,
...options,
redisConfig,
});
}
/**
* Create a cache for indicators with longer TTL
*/
export function createIndicatorCache(options: Partial<CacheOptions> = {}): CacheProvider {
export function createIndicatorCache(redisConfig: RedisConfig, options?: Partial<Omit<CacheOptions, 'redisConfig'>>): CacheProvider {
return createCache({
keyPrefix: 'indicators:',
ttl: 1800, // 30 minutes for indicators
enableMetrics: true,
shared: true,
...options,
redisConfig,
});
}
@ -81,6 +84,7 @@ export type {
CacheStats,
CacheKey,
SerializationOptions,
RedisConfig,
} from './types';
export { RedisCache } from './redis-cache';

View file

@ -25,7 +25,7 @@ export class RedisCache implements CacheProvider {
uptime: 0,
};
constructor(options: CacheOptions = {}) {
constructor(options: CacheOptions) {
this.defaultTTL = options.ttl ?? 3600; // 1 hour default
this.keyPrefix = options.keyPrefix ?? 'cache:';
this.enableMetrics = options.enableMetrics ?? true;
@ -46,6 +46,7 @@ export class RedisCache implements CacheProvider {
this.redis = this.connectionManager.getConnection({
name: `${baseName}-SERVICE`,
singleton: options.shared ?? true, // Default to shared connection for cache
redisConfig: options.redisConfig,
});
// Only setup event handlers for non-shared connections to avoid memory leaks

View file

@ -1,3 +1,23 @@
export interface RedisConfig {
host: string;
port: number;
password?: string;
username?: string;
db?: number;
keyPrefix?: string;
maxRetriesPerRequest?: number;
retryDelayOnFailover?: number;
connectTimeout?: number;
commandTimeout?: number;
keepAlive?: number;
tls?: {
cert?: string;
key?: string;
ca?: string;
rejectUnauthorized?: boolean;
};
}
export interface CacheProvider {
get<T>(key: string): Promise<T | null>;
set<T>(
@ -64,6 +84,7 @@ export interface CacheOptions {
enableMetrics?: boolean;
name?: string; // Name for connection identification
shared?: boolean; // Whether to use shared connection
redisConfig: RedisConfig;
}
export interface CacheStats {