import { ProxyInfo } from 'libs/http/src/types'; import { ProviderConfig } from '../services/provider-registry.service'; import { getLogger } from '@stock-bot/logger'; import { BatchProcessor } from '../utils/batch-processor'; // Create logger for this provider const logger = getLogger('proxy-provider'); // This will run at the same time each day as when the app started const getEvery24HourCron = (): string => { const now = new Date(); const hours = now.getHours(); const minutes = now.getMinutes(); return `${minutes} ${hours} * * *`; // Every day at startup time }; export const proxyProvider: ProviderConfig = { name: 'proxy-service', service: 'proxy', operations: { 'fetch-and-check': async (payload: { sources?: string[] }) => { const { proxyService } = await import('./proxy.tasks'); const { queueManager } = await import('../services/queue.service'); await queueManager.drainQueue(); const proxies = await proxyService.fetchProxiesFromSources(); const proxiesCount = proxies.length; if (proxiesCount === 0) { logger.info('No proxies fetched, skipping job creation'); return { proxiesFetched: 0, jobsCreated: 0 }; } const batchProcessor = new BatchProcessor(queueManager); // Environment-configurable settings const targetHours = parseInt(process.env.PROXY_VALIDATION_HOURS || '8'); const batchSize = parseInt(process.env.PROXY_BATCH_SIZE || '200'); const useDirectMode = process.env.PROXY_DIRECT_MODE === 'true'; logger.info('Proxy validation configuration', { targetHours, batchSize, useDirectMode, totalProxies: proxies.length }); if (useDirectMode) { // Direct approach - simpler, creates all jobs immediately const result = await batchProcessor.createDirectJobs({ items: proxies, batchSize: 0, // Not used in direct mode totalDelayMs: targetHours * 60 * 60 * 1000, jobNamePrefix: 'proxy', operation: 'check-proxy', service: 'proxy', provider: 'proxy-service', priority: 2, createJobData: (proxy: ProxyInfo) => ({ proxy, source: 'fetch-and-check' }), removeOnComplete: 5, removeOnFail: 3 }); return { proxiesFetched: result.totalItems, jobsCreated: result.jobsCreated, mode: 'direct' }; } else { // Batch approach - creates batch jobs that create individual jobs const result = await batchProcessor.createBatchJobs({ items: proxies, batchSize, totalDelayMs: targetHours * 60 * 60 * 1000, jobNamePrefix: 'proxy', operation: 'check-proxy', service: 'proxy', provider: 'proxy-service', priority: 3, createJobData: (proxy: ProxyInfo) => ({ proxy, source: 'fetch-and-check' }), removeOnComplete: 3, removeOnFail: 5 }); return { proxiesFetched: result.totalItems, batchJobsCreated: result.batchJobsCreated, totalBatches: result.totalBatches, estimatedDurationHours: result.estimatedDurationHours, mode: 'batch' }; } }, 'process-proxy-batch': async (payload: any) => { const { queueManager } = await import('../services/queue.service'); const batchProcessor = new BatchProcessor(queueManager); return await batchProcessor.processBatch( payload, (proxy: ProxyInfo, index: number) => ({ proxy, source: payload.config?.source || 'batch-processing' }) ); }, 'check-proxy': async (payload: { proxy: ProxyInfo, source?: string, batchIndex?: number, itemIndex?: number, total?: number }) => { const { checkProxy } = await import('./proxy.tasks'); try { const result = await checkProxy(payload.proxy); logger.debug('Proxy validated', { proxy: `${payload.proxy.host}:${payload.proxy.port}`, isWorking: result.isWorking, responseTime: result.responseTime, batchIndex: payload.batchIndex }); return { result, proxy: payload.proxy, // Only include batch info if it exists (for batch mode) ...(payload.batchIndex !== undefined && { batchInfo: { batchIndex: payload.batchIndex, itemIndex: payload.itemIndex, total: payload.total, source: payload.source } }) }; } catch (error) { logger.warn('Proxy validation failed', { proxy: `${payload.proxy.host}:${payload.proxy.port}`, error: error instanceof Error ? error.message : String(error), batchIndex: payload.batchIndex }); return { result: { isWorking: false, error: String(error) }, proxy: payload.proxy, // Only include batch info if it exists (for batch mode) ...(payload.batchIndex !== undefined && { batchInfo: { batchIndex: payload.batchIndex, itemIndex: payload.itemIndex, total: payload.total, source: payload.source } }) }; } } }, scheduledJobs: [ { type: 'proxy-maintenance', operation: 'fetch-and-check', payload: {}, cronPattern: getEvery24HourCron(), priority: 5, immediately: true, description: 'Fetch and validate proxy list from sources' } ] };