stock-bot/apps/data-service/src/providers/proxy.provider.ts
2025-06-09 00:01:16 -04:00

180 lines
5.7 KiB
TypeScript

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'
}
]
};