Skip to main content
Glama
provider-health.ts5.18 kB
import { env } from './env.js'; import { logger } from '../logging/logger.js'; import { ModelProvider } from './models.js'; import { providerManager } from './provider-manager.js'; /** * Provider health status tracker */ export class ProviderHealthManager { private healthStatus: Map<ModelProvider, boolean> = new Map(); private lastCheckTime: Map<ModelProvider, number> = new Map(); private readonly CHECK_INTERVAL = 60000; // 1 minute /** * Check if a provider is healthy/available */ async isProviderHealthy(provider: ModelProvider): Promise<boolean> { const lastCheck = this.lastCheckTime.get(provider) || 0; const now = Date.now(); // Use cached result if checked recently if (now - lastCheck < this.CHECK_INTERVAL && this.healthStatus.has(provider)) { return this.healthStatus.get(provider)!; } // Perform actual health check const isHealthy = await this.checkProviderHealth(provider); this.healthStatus.set(provider, isHealthy); this.lastCheckTime.set(provider, now); // Update database await providerManager.updateHealthStatus(provider, isHealthy); return isHealthy; } /** * Perform actual health check for a provider */ private async checkProviderHealth(provider: ModelProvider): Promise<boolean> { try { switch (provider) { case 'openai': { // Check database first const apiKey = await providerManager.getApiKey('openai'); if (!apiKey && !env.OPENAI_API_KEY) return false; return true; } case 'anthropic': { // Check database first const apiKey = await providerManager.getApiKey('anthropic'); if (!apiKey && !env.ANTHROPIC_API_KEY) return false; return true; } case 'openrouter': { // Check database first const apiKey = await providerManager.getApiKey('openrouter'); if (!apiKey && !env.OPENROUTER_API_KEY) return false; return true; } case 'oss-local': if (!env.OSS_MODEL_ENABLED) return false; try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); const response = await fetch(env.OSS_MODEL_ENDPOINT + '/api/tags', { signal: controller.signal, }); clearTimeout(timeoutId); return response.ok; } catch { return false; } default: return false; } } catch (error) { logger.warn(`Health check failed for ${provider}: ${error}`); return false; } } /** * Mark a provider as unhealthy (e.g., after a failed request) */ markProviderUnhealthy(provider: ModelProvider): void { this.healthStatus.set(provider, false); this.lastCheckTime.set(provider, Date.now()); logger.warn(`Provider ${provider} marked as unhealthy`); } /** * Reset a provider's health status (force recheck on next call) */ resetProvider(provider: ModelProvider): void { this.healthStatus.delete(provider); this.lastCheckTime.delete(provider); logger.info(`Provider ${provider} health status reset`); } /** * Get all healthy providers */ async getHealthyProviders(): Promise<ModelProvider[]> { const providers: ModelProvider[] = ['openai', 'anthropic', 'openrouter', 'oss-local']; const healthy: ModelProvider[] = []; for (const provider of providers) { if (await this.isProviderHealthy(provider)) { healthy.push(provider); } } return healthy; } /** * Force refresh health status for all providers */ async refreshAllProviders(): Promise<void> { const providers: ModelProvider[] = ['openai', 'anthropic', 'openrouter', 'oss-local']; logger.info('Checking LLM provider connectivity...'); for (const provider of providers) { this.lastCheckTime.delete(provider); // Force recheck const isHealthy = await this.isProviderHealthy(provider); const status = isHealthy ? '✅ Available' : '❌ Unavailable'; logger.info(`${provider}: ${status}`); } } /** * Get provider status summary */ getProviderStatusSummary(): Record<string, boolean> { const summary: Record<string, boolean> = {}; this.healthStatus.forEach((healthy, provider) => { summary[provider] = healthy; }); return summary; } } // Singleton instance export const providerHealth = new ProviderHealthManager();

Latest Blog Posts

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