Skip to main content
Glama
redis.ts5.97 kB
import Redis from 'ioredis'; import { env } from '../config/env.js'; import { logger } from '../logging/logger.js'; /** * Redis client singleton for caching */ class RedisCache { private client: Redis | null = null; private isConnected = false; constructor() { this.initialize(); } private initialize() { try { this.client = new Redis({ host: env.REDIS_HOST || 'localhost', port: parseInt(env.REDIS_PORT || '6379'), password: env.REDIS_PASSWORD || undefined, db: parseInt(env.REDIS_DB || '0'), retryStrategy: (times) => { const delay = Math.min(times * 50, 2000); return delay; }, maxRetriesPerRequest: 3, }); this.client.on('connect', () => { this.isConnected = true; logger.info('Redis connected successfully'); }); this.client.on('error', (error) => { this.isConnected = false; logger.error('Redis connection error', { error: error.message }); }); this.client.on('close', () => { this.isConnected = false; logger.warn('Redis connection closed'); }); } catch (error) { logger.error('Failed to initialize Redis', { error: error instanceof Error ? error.message : 'Unknown error', }); } } /** * Get value from cache */ async get<T = string>(key: string): Promise<T | null> { if (!this.client || !this.isConnected) { logger.debug('Redis not available for GET', { key }); return null; } try { const value = await this.client.get(key); if (!value) return null; // Try to parse as JSON, fallback to string try { return JSON.parse(value) as T; } catch { return value as T; } } catch (error) { logger.error('Redis GET error', { key, error: error instanceof Error ? error.message : 'Unknown', }); return null; } } /** * Set value in cache with optional TTL (in seconds) */ async set(key: string, value: unknown, ttl?: number): Promise<boolean> { if (!this.client || !this.isConnected) { logger.debug('Redis not available for SET', { key }); return false; } try { const serialized = typeof value === 'string' ? value : JSON.stringify(value); if (ttl) { await this.client.setex(key, ttl, serialized); } else { await this.client.set(key, serialized); } return true; } catch (error) { logger.error('Redis SET error', { key, error: error instanceof Error ? error.message : 'Unknown', }); return false; } } /** * Delete key from cache */ async del(key: string): Promise<boolean> { if (!this.client || !this.isConnected) { logger.debug('Redis not available for DEL', { key }); return false; } try { await this.client.del(key); return true; } catch (error) { logger.error('Redis DEL error', { key, error: error instanceof Error ? error.message : 'Unknown', }); return false; } } /** * Check if key exists */ async exists(key: string): Promise<boolean> { if (!this.client || !this.isConnected) { return false; } try { const result = await this.client.exists(key); return result === 1; } catch (error) { logger.error('Redis EXISTS error', { key, error: error instanceof Error ? error.message : 'Unknown', }); return false; } } /** * Get multiple keys */ async mget<T = string>(keys: string[]): Promise<(T | null)[]> { if (!this.client || !this.isConnected || keys.length === 0) { return keys.map(() => null); } try { const values = await this.client.mget(...keys); return values.map((value) => { if (!value) return null; try { return JSON.parse(value) as T; } catch { return value as T; } }); } catch (error) { logger.error('Redis MGET error', { error: error instanceof Error ? error.message : 'Unknown', }); return keys.map(() => null); } } /** * Close Redis connection */ async close(): Promise<void> { if (this.client) { await this.client.quit(); this.isConnected = false; logger.info('Redis connection closed'); } } /** * Check if Redis is connected */ isReady(): boolean { return this.isConnected; } } // Singleton instance export const redisCache = new RedisCache(); /** * Cache key builders for consistent naming */ export const CacheKeys = { llmResponse: (modelId: string, promptHash: string) => `llm:cache:${modelId}:${promptHash}`, conversationSummary: (conversationId: string) => `conv:summary:${conversationId}`, routingHints: (projectId: string) => `routing:hints:${projectId}`, contextMessages: (conversationId: string) => `conv:messages:${conversationId}`, todoList: (conversationId: string) => `todo:list:${conversationId}`, };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/babasida246/ai-mcp-gateway'

If you have feedback or need assistance with the MCP directory API, please join our Discord server