UNPKG

falkordb-mcpserver

Version:

Model Context Protocol server for FalkorDB graph databases - enables AI assistants to query and manage graph data using natural language

131 lines (130 loc) 5.35 kB
import { createClient } from 'redis'; import { config } from '../config/index.js'; import { AppError, CommonErrors } from '../errors/AppError.js'; import { logger } from './logger.service.js'; class RedisService { client = null; maxRetries = 5; retryCount = 0; isInitializing = false; constructor() { // Don't initialize in constructor - use explicit initialization } async initialize() { if (this.isInitializing) { return; } this.isInitializing = true; try { logger.info('Attempting to connect to Redis', { url: config.redis.url, attempt: this.retryCount + 1 }); this.client = createClient({ url: config.redis.url, username: config.redis.username, password: config.redis.password, }); await this.client.connect(); await this.client.ping(); logger.info('Successfully connected to Redis'); this.retryCount = 0; this.isInitializing = false; } catch (error) { this.isInitializing = false; if (this.retryCount < this.maxRetries) { this.retryCount++; logger.warn('Failed to connect to Redis, retrying...', { attempt: this.retryCount, maxRetries: this.maxRetries, error: error instanceof Error ? error.message : String(error) }); await new Promise(resolve => setTimeout(resolve, 5000)); return this.initialize(); } else { const appError = new AppError(CommonErrors.CONNECTION_FAILED, `Failed to connect to Redis after ${this.maxRetries} attempts: ${error instanceof Error ? error.message : String(error)}`, true); logger.error('Redis connection failed permanently', appError); throw appError; } } } async get(key) { if (!this.client) { throw new AppError(CommonErrors.CONNECTION_FAILED, 'Redis client not initialized. Call initialize() first.', true); } try { const value = await this.client.get(key); logger.debug('Redis GET operation completed', { key, hasValue: value !== null }); return value; } catch (error) { const appError = new AppError(CommonErrors.OPERATION_FAILED, `Failed to get key '${key}' from Redis: ${error instanceof Error ? error.message : String(error)}`, true); logger.error('Redis GET operation failed', appError, { key }); throw appError; } } async set(key, value) { if (!this.client) { throw new AppError(CommonErrors.CONNECTION_FAILED, 'Redis client not initialized. Call initialize() first.', true); } try { await this.client.set(key, value); logger.debug('Redis SET operation completed', { key }); } catch (error) { const appError = new AppError(CommonErrors.OPERATION_FAILED, `Failed to set key '${key}' in Redis: ${error instanceof Error ? error.message : String(error)}`, true); logger.error('Redis SET operation failed', appError, { key }); throw appError; } } async delete(key) { if (!this.client) { throw new AppError(CommonErrors.CONNECTION_FAILED, 'Redis client not initialized. Call initialize() first.', true); } try { await this.client.del(key); logger.debug('Redis DEL operation completed', { key }); } catch (error) { const appError = new AppError(CommonErrors.OPERATION_FAILED, `Failed to delete key '${key}' from Redis: ${error instanceof Error ? error.message : String(error)}`, true); logger.error('Redis DEL operation failed', appError, { key }); throw appError; } } async listKeys() { if (!this.client) { throw new AppError(CommonErrors.CONNECTION_FAILED, 'Redis client not initialized. Call initialize() first.', true); } try { const result = await this.client.scan(0, { MATCH: '*', COUNT: 1000 }); logger.debug('Redis KEYS operation completed', { count: result.keys.length }); return result.keys; } catch (error) { const appError = new AppError(CommonErrors.OPERATION_FAILED, `Failed to list keys in Redis: ${error instanceof Error ? error.message : String(error)}`, true); logger.error('Redis KEYS operation failed', appError); throw appError; } } async close() { if (this.client) { try { await this.client.quit(); logger.info('Redis connection closed successfully'); } catch (error) { logger.error('Error closing Redis connection', error instanceof Error ? error : new Error(String(error))); } finally { this.client = null; this.retryCount = 0; } } } } export const redisService = new RedisService();