UNPKG

@felixgeelhaar/govee-api-client

Version:

Enterprise-grade TypeScript client library for the Govee Developer REST API

295 lines 11.2 kB
/** * Integration Guide for Retry Logic with Govee API Client * * This file provides comprehensive examples and integration patterns for * adding retry logic to the Govee API client after rate limiting is implemented. */ import { GoveeDeviceRepository } from '../GoveeDeviceRepository'; import { GoveeControlService } from '../../services/GoveeControlService'; import { RetryPolicy, RetryExecutor, RetryableRepository, RetryConfigPresets, RetryExecutorFactory, } from './index'; /** * INTEGRATION EXAMPLE 1: Basic Retry-Enabled Repository * * This example shows how to wrap the existing GoveeDeviceRepository * with retry functionality using default Govee API optimized settings. */ export function createBasicRetryRepository(apiKey, logger) { // Create the base repository const baseRepository = new GoveeDeviceRepository({ apiKey, timeout: 30000, logger, }); // Wrap with retry functionality const retryableRepository = new RetryableRepository({ repository: baseRepository, retryExecutor: RetryExecutorFactory.createForGoveeApi(logger), logger, enableRequestIds: true, }); return retryableRepository; } /** * INTEGRATION EXAMPLE 2: Production-Ready Service with Retry Logic * * This example shows how to integrate retry logic into the GoveeControlService * for production environments with conservative retry policies. */ export function createProductionGoveeService(apiKey, logger) { // Create base repository const baseRepository = new GoveeDeviceRepository({ apiKey, timeout: 30000, logger, }); // Create production-optimized retry executor const retryPolicy = RetryPolicy.createConservative(logger); const retryExecutor = new RetryExecutor(retryPolicy, { logger, enableRequestLogging: true, enablePerformanceTracking: true, }); // Wrap repository with retry logic const retryableRepository = new RetryableRepository({ repository: baseRepository, retryExecutor, logger, }); // Create service with retry-enabled repository return new GoveeControlService({ repository: retryableRepository, rateLimit: 100, // 100 requests per minute logger, }); } /** * INTEGRATION EXAMPLE 3: Custom Retry Configuration for Specific Use Cases * * This example demonstrates creating custom retry policies for different * operational scenarios. */ export class CustomRetryConfigurations { /** * Configuration for bulk operations that need to be resilient */ static createBulkOperationConfig(logger) { const builder = RetryConfigPresets.custom() .withExponentialBackoff(2000, 60000, 1.5) // Start at 2s, max 1min, gentle growth .withDecorrelatedJitter(0.2) // Sophisticated jitter .withBasicConditions(5, 300000, [429, 502, 503, 504]) // 5 attempts, 5min total .withBasicCircuitBreaker(7, 60000, 3) // Higher failure threshold .withMetrics(true); if (logger) { builder.withLogger(logger); } return new RetryPolicy(builder.build()); } /** * Configuration for real-time operations that need fast failure */ static createRealTimeConfig(logger) { const builder = RetryConfigPresets.custom() .withLinearBackoff(500, 2000) // Quick linear backoff .withEqualJitter(0.1) // Low jitter .withBasicConditions(2, 5000, [429, 503, 504]) // Quick failure .withBasicCircuitBreaker(3, 10000, 1) // Fast circuit breaking .withMetrics(true); if (logger) { builder.withLogger(logger); } return new RetryPolicy(builder.build()); } /** * Configuration optimized for rate-limited APIs */ static createRateLimitOptimizedConfig(logger) { return new RetryPolicy(RetryConfigPresets.rateLimitAware(logger)); } } /** * INTEGRATION EXAMPLE 4: Service with Multiple Retry Strategies * * This example shows how to use different retry strategies for different * types of operations within the same service. */ export class AdvancedGoveeService { constructor(apiKey, logger) { this.logger = logger; // Create base repository this.baseRepository = new GoveeDeviceRepository({ apiKey, timeout: 30000, logger, }); // Create bulk operations repository (resilient, slower) const bulkRetryExecutor = new RetryExecutor(CustomRetryConfigurations.createBulkOperationConfig(logger), { logger, enableRequestLogging: true, enablePerformanceTracking: true }); this.bulkRepository = new RetryableRepository({ repository: this.baseRepository, retryExecutor: bulkRetryExecutor, logger, }); // Create real-time repository (fast failure) const realTimeRetryExecutor = new RetryExecutor(CustomRetryConfigurations.createRealTimeConfig(logger), { logger, enableRequestLogging: true, enablePerformanceTracking: true }); this.realTimeRepository = new RetryableRepository({ repository: this.baseRepository, retryExecutor: realTimeRetryExecutor, logger, }); } /** * Bulk device discovery with resilient retry logic */ async discoverAllDevices() { this.logger.info('Starting bulk device discovery'); const result = await this.bulkRepository.findAllWithRetryResult(); this.logger.info({ devices: result.data?.length || 0, attempts: result.totalAttempts, totalTime: result.totalTimeMs, success: result.success, }, 'Bulk device discovery completed'); if (!result.success) { throw result.error; } return result.data; } /** * Real-time device state check with fast failure */ async getDeviceStateRealTime(deviceId, sku) { this.logger.debug({ deviceId, sku }, 'Getting device state (real-time)'); const result = await this.realTimeRepository.findStateWithRetryResult(deviceId, sku); if (!result.success) { this.logger.warn({ deviceId, sku, attempts: result.totalAttempts, error: result.error?.toObject(), }, 'Real-time state check failed'); throw result.error; } return result.data; } /** * Get comprehensive retry metrics across all strategies */ getRetryMetrics() { return { bulk: this.bulkRepository.getRetryMetrics(), realTime: this.realTimeRepository.getRetryMetrics(), }; } /** * Reset all retry metrics */ resetMetrics() { this.bulkRepository.resetRetryMetrics(); this.realTimeRepository.resetRetryMetrics(); } } /** * INTEGRATION EXAMPLE 5: Monitoring and Observability Integration * * This example shows how to integrate retry metrics with monitoring systems. */ export class RetryMetricsCollector { constructor(retryableRepository, logger, metricsIntervalMs = 60000 // 1 minute ) { this.retryableRepository = retryableRepository; this.logger = logger; this.metricsIntervalMs = metricsIntervalMs; } /** * Start collecting and logging retry metrics */ startMetricsCollection() { this.metricsInterval = setInterval(() => { const metrics = this.retryableRepository.getRetryMetrics(); this.logger.info({ retry_metrics: { total_attempts: metrics.totalAttempts, successful_retries: metrics.successfulRetries, failed_retries: metrics.failedRetries, total_retry_time_ms: metrics.totalRetryTimeMs, average_retry_delay_ms: metrics.averageRetryDelayMs, circuit_breaker_state: metrics.circuitBreakerState, success_rate: metrics.totalAttempts > 0 ? metrics.successfulRetries / metrics.totalAttempts : 0, }, }, 'Retry metrics collected'); }, this.metricsIntervalMs); } /** * Stop metrics collection */ stopMetricsCollection() { if (this.metricsInterval) { clearInterval(this.metricsInterval); this.metricsInterval = undefined; } } /** * Get current metrics snapshot */ getMetricsSnapshot() { const metrics = this.retryableRepository.getRetryMetrics(); return { timestamp: new Date().toISOString(), total_attempts: metrics.totalAttempts, successful_retries: metrics.successfulRetries, failed_retries: metrics.failedRetries, success_rate: metrics.totalAttempts > 0 ? (metrics.successfulRetries / metrics.totalAttempts) * 100 : 0, average_retry_delay_ms: metrics.averageRetryDelayMs, circuit_breaker_state: metrics.circuitBreakerState, last_error: metrics.lastError?.toObject(), last_retry: metrics.lastRetryTimestamp?.toISOString(), }; } } /** * INTEGRATION EXAMPLE 6: Environment-Specific Configuration Factory * * This factory creates appropriate retry configurations based on environment. */ export class RetryConfigFactory { /** * Create retry configuration based on environment */ static createForEnvironment(environment, logger) { switch (environment) { case 'development': return new RetryPolicy(RetryConfigPresets.development(logger)); case 'testing': return new RetryPolicy(RetryConfigPresets.testing(logger)); case 'staging': // Use production-like settings but with more logging return new RetryPolicy({ ...RetryConfigPresets.production(logger), enableMetrics: true, }); case 'production': return new RetryPolicy(RetryConfigPresets.production(logger)); default: throw new Error(`Unknown environment: ${environment}`); } } /** * Create retry configuration for specific use cases */ static createForUseCase(useCase, logger) { switch (useCase) { case 'bulk': return CustomRetryConfigurations.createBulkOperationConfig(logger); case 'realtime': return CustomRetryConfigurations.createRealTimeConfig(logger); case 'background': return new RetryPolicy(RetryConfigPresets.networkResilient(logger)); case 'interactive': return new RetryPolicy(RetryConfigPresets.highFrequency(logger)); default: throw new Error(`Unknown use case: ${useCase}`); } } } // Re-export for convenience export { RetryExecutorFactory } from './RetryableRequest'; //# sourceMappingURL=IntegrationGuide.js.map