Initial proxy manager refactor
This commit is contained in:
parent
84cb14680b
commit
da916222c1
6 changed files with 58 additions and 37 deletions
|
|
@ -11,6 +11,7 @@ import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger';
|
||||||
import { connectMongoDB } from '@stock-bot/mongodb-client';
|
import { connectMongoDB } from '@stock-bot/mongodb-client';
|
||||||
import { connectPostgreSQL } from '@stock-bot/postgres-client';
|
import { connectPostgreSQL } from '@stock-bot/postgres-client';
|
||||||
import { QueueManager, type QueueManagerConfig } from '@stock-bot/queue';
|
import { QueueManager, type QueueManagerConfig } from '@stock-bot/queue';
|
||||||
|
import { ProxyManager } from '@stock-bot/utils';
|
||||||
import { Shutdown } from '@stock-bot/shutdown';
|
import { Shutdown } from '@stock-bot/shutdown';
|
||||||
// Local imports
|
// Local imports
|
||||||
import { exchangeRoutes, healthRoutes, queueRoutes } from './routes';
|
import { exchangeRoutes, healthRoutes, queueRoutes } from './routes';
|
||||||
|
|
@ -116,8 +117,7 @@ async function initializeServices() {
|
||||||
|
|
||||||
// Initialize proxy manager
|
// Initialize proxy manager
|
||||||
logger.debug('Initializing proxy manager...');
|
logger.debug('Initializing proxy manager...');
|
||||||
const { proxyManager } = await import('@stock-bot/utils');
|
await ProxyManager.initialize();
|
||||||
await proxyManager.initialize();
|
|
||||||
logger.info('Proxy manager initialized');
|
logger.info('Proxy manager initialized');
|
||||||
|
|
||||||
// Initialize providers (register handlers and scheduled jobs)
|
// Initialize providers (register handlers and scheduled jobs)
|
||||||
|
|
@ -257,4 +257,4 @@ startServer().catch(error => {
|
||||||
|
|
||||||
logger.info('Data service startup initiated');
|
logger.info('Data service startup initiated');
|
||||||
|
|
||||||
// Queue manager is available via QueueManager.getInstance() singleton pattern
|
// ProxyManager class and singleton instance are available via @stock-bot/utils
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { getRandomUserAgent } from '@stock-bot/http';
|
||||||
import { getLogger } from '@stock-bot/logger';
|
import { getLogger } from '@stock-bot/logger';
|
||||||
import { getMongoDBClient } from '@stock-bot/mongodb-client';
|
import { getMongoDBClient } from '@stock-bot/mongodb-client';
|
||||||
import { QueueManager } from '@stock-bot/queue';
|
import { QueueManager } from '@stock-bot/queue';
|
||||||
import { proxyManager } from '@stock-bot/utils';
|
import { ProxyManager } from '@stock-bot/utils';
|
||||||
|
|
||||||
// Shared instances (module-scoped, not global)
|
// Shared instances (module-scoped, not global)
|
||||||
let isInitialized = false; // Track if resources are initialized
|
let isInitialized = false; // Track if resources are initialized
|
||||||
|
|
@ -90,7 +90,7 @@ export async function createSessions(): Promise<void> {
|
||||||
|
|
||||||
while (sessionCache[sessionId].length < 50) {
|
while (sessionCache[sessionId].length < 50) {
|
||||||
logger.info(`Creating new session for ${sessionId}`);
|
logger.info(`Creating new session for ${sessionId}`);
|
||||||
const proxyInfo = await proxyManager.getRandomProxy();
|
const proxyInfo = await ProxyManager.getInstance().getRandomProxy();
|
||||||
if (!proxyInfo) {
|
if (!proxyInfo) {
|
||||||
logger.error('No proxy available for QM session creation');
|
logger.error('No proxy available for QM session creation');
|
||||||
break; // Skip session creation if no proxy is available
|
break; // Skip session creation if no proxy is available
|
||||||
|
|
@ -294,7 +294,7 @@ async function searchAndSpawnJobs(
|
||||||
|
|
||||||
// API call function to search symbols via QM
|
// API call function to search symbols via QM
|
||||||
async function searchQMSymbolsAPI(query: string): Promise<string[]> {
|
async function searchQMSymbolsAPI(query: string): Promise<string[]> {
|
||||||
const proxyInfo = await proxyManager.getRandomProxy();
|
const proxyInfo = await ProxyManager.getInstance().getRandomProxy();
|
||||||
|
|
||||||
if (!proxyInfo) {
|
if (!proxyInfo) {
|
||||||
throw new Error('No proxy available for QM API call');
|
throw new Error('No proxy available for QM API call');
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import {
|
||||||
handlerRegistry,
|
handlerRegistry,
|
||||||
type HandlerConfigWithSchedule,
|
type HandlerConfigWithSchedule,
|
||||||
} from '@stock-bot/queue';
|
} from '@stock-bot/queue';
|
||||||
import { proxyManager } from '@stock-bot/utils';
|
import { ProxyManager } from '@stock-bot/utils';
|
||||||
|
|
||||||
const logger = getLogger('webshare-provider');
|
const logger = getLogger('webshare-provider');
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ export function initializeWebShareProvider() {
|
||||||
|
|
||||||
if (proxies.length > 0) {
|
if (proxies.length > 0) {
|
||||||
// Update the centralized proxy manager
|
// Update the centralized proxy manager
|
||||||
await proxyManager.updateProxies(proxies);
|
await ProxyManager.getInstance().updateProxies(proxies);
|
||||||
|
|
||||||
logger.info('Updated proxy manager with WebShare proxies', {
|
logger.info('Updated proxy manager with WebShare proxies', {
|
||||||
count: proxies.length,
|
count: proxies.length,
|
||||||
|
|
@ -66,7 +66,7 @@ export function initializeWebShareProvider() {
|
||||||
const validationResults = await validateStoredProxies();
|
const validationResults = await validateStoredProxies();
|
||||||
|
|
||||||
// Update proxy manager with validated proxies
|
// Update proxy manager with validated proxies
|
||||||
await proxyManager.updateProxies(validationResults.workingProxies);
|
await ProxyManager.getInstance().updateProxies(validationResults.workingProxies);
|
||||||
|
|
||||||
logger.info('Proxy validation completed', {
|
logger.info('Proxy validation completed', {
|
||||||
totalChecked: validationResults.totalChecked,
|
totalChecked: validationResults.totalChecked,
|
||||||
|
|
@ -87,7 +87,7 @@ export function initializeWebShareProvider() {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
'get-stats': createJobHandler(async () => {
|
'get-stats': createJobHandler(async () => {
|
||||||
const stats = proxyManager.getStats();
|
const stats = ProxyManager.getInstance().getStats();
|
||||||
logger.info('Proxy manager statistics', stats);
|
logger.info('Proxy manager statistics', stats);
|
||||||
return stats;
|
return stats;
|
||||||
}),
|
}),
|
||||||
|
|
@ -128,7 +128,7 @@ export function initializeWebShareProvider() {
|
||||||
|
|
||||||
// Legacy function for backward compatibility - now uses centralized proxy manager
|
// Legacy function for backward compatibility - now uses centralized proxy manager
|
||||||
export async function getProxy(): Promise<string | null> {
|
export async function getProxy(): Promise<string | null> {
|
||||||
const proxy = await proxyManager.getRandomProxy();
|
const proxy = ProxyManager.getInstance().getRandomProxy();
|
||||||
if (!proxy) {
|
if (!proxy) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import { getLogger } from '@stock-bot/logger';
|
import { getLogger } from '@stock-bot/logger';
|
||||||
import { HttpClient, type ProxyInfo } from '@stock-bot/http';
|
import { HttpClient, type ProxyInfo } from '@stock-bot/http';
|
||||||
import { proxyManager } from '@stock-bot/utils';
|
import { ProxyManager } from '@stock-bot/utils';
|
||||||
|
|
||||||
const logger = getLogger('webshare-tasks');
|
const logger = getLogger('webshare-tasks');
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ export async function validateStoredProxies(): Promise<{
|
||||||
const testUrl = 'https://httpbin.org/ip'; // Simple IP echo service
|
const testUrl = 'https://httpbin.org/ip'; // Simple IP echo service
|
||||||
|
|
||||||
// Get all proxies from proxy manager
|
// Get all proxies from proxy manager
|
||||||
const allProxies = await proxyManager.getAllProxies();
|
const allProxies = ProxyManager.getInstance().getAllProxies();
|
||||||
|
|
||||||
if (allProxies.length === 0) {
|
if (allProxies.length === 0) {
|
||||||
logger.warn('No proxies available for validation');
|
logger.warn('No proxies available for validation');
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* Proxy management utilities
|
* Proxy management utilities
|
||||||
*/
|
*/
|
||||||
export { ProxyManager, proxyManager } from './proxy-manager';
|
export { default as ProxyManager } from './proxy-manager';
|
||||||
export type { ProxyInfo } from '@stock-bot/http'; // Re-export for convenience
|
export type { ProxyInfo } from '@stock-bot/http'; // Re-export for convenience
|
||||||
|
|
@ -9,12 +9,13 @@ import type { ProxyInfo } from '@stock-bot/http';
|
||||||
const logger = getLogger('proxy-manager');
|
const logger = getLogger('proxy-manager');
|
||||||
|
|
||||||
export class ProxyManager {
|
export class ProxyManager {
|
||||||
|
private static instance: ProxyManager | null = null;
|
||||||
private cache: CacheProvider;
|
private cache: CacheProvider;
|
||||||
private proxies: ProxyInfo[] = [];
|
private proxies: ProxyInfo[] = [];
|
||||||
private lastUpdate: Date | null = null;
|
private lastUpdate: Date | null = null;
|
||||||
private isInitialized = false;
|
private isInitialized = false;
|
||||||
|
|
||||||
constructor() {
|
private constructor() {
|
||||||
const databaseConfig = getDatabaseConfig();
|
const databaseConfig = getDatabaseConfig();
|
||||||
this.cache = createCache({
|
this.cache = createCache({
|
||||||
redisConfig: databaseConfig.dragonfly,
|
redisConfig: databaseConfig.dragonfly,
|
||||||
|
|
@ -25,9 +26,9 @@ export class ProxyManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the proxy manager - loads existing proxies from cache
|
* Internal initialization - loads existing proxies from cache
|
||||||
*/
|
*/
|
||||||
async initialize(): Promise<void> {
|
private async initializeInternal(): Promise<void> {
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -47,17 +48,18 @@ export class ProxyManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a random working proxy from the available pool
|
* Get a random working proxy from the available pool (synchronous)
|
||||||
*/
|
*/
|
||||||
async getRandomProxy(): Promise<ProxyInfo | null> {
|
getRandomProxy(): ProxyInfo | null {
|
||||||
// Ensure initialized
|
// Ensure initialized
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
await this.initialize();
|
throw new Error('ProxyManager not initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load from cache if memory is empty
|
// Return null if no proxies available
|
||||||
if (this.proxies.length === 0) {
|
if (this.proxies.length === 0) {
|
||||||
await this.loadFromCache();
|
logger.warn('No proxies available in memory');
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter for working proxies (not explicitly marked as non-working)
|
// Filter for working proxies (not explicitly marked as non-working)
|
||||||
|
|
@ -96,15 +98,11 @@ export class ProxyManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all working proxies
|
* Get all working proxies (synchronous)
|
||||||
*/
|
*/
|
||||||
async getWorkingProxies(): Promise<ProxyInfo[]> {
|
getWorkingProxies(): ProxyInfo[] {
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
await this.initialize();
|
throw new Error('ProxyManager not initialized');
|
||||||
}
|
|
||||||
|
|
||||||
if (this.proxies.length === 0) {
|
|
||||||
await this.loadFromCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.proxies.filter(proxy => proxy.isWorking !== false);
|
return this.proxies.filter(proxy => proxy.isWorking !== false);
|
||||||
|
|
@ -113,13 +111,9 @@ export class ProxyManager {
|
||||||
/**
|
/**
|
||||||
* Get all proxies (working and non-working)
|
* Get all proxies (working and non-working)
|
||||||
*/
|
*/
|
||||||
async getAllProxies(): Promise<ProxyInfo[]> {
|
getAllProxies(): ProxyInfo[] {
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
await this.initialize();
|
throw new Error('ProxyManager not initialized');
|
||||||
}
|
|
||||||
|
|
||||||
if (this.proxies.length === 0) {
|
|
||||||
await this.loadFromCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...this.proxies];
|
return [...this.proxies];
|
||||||
|
|
@ -250,7 +244,34 @@ export class ProxyManager {
|
||||||
logger.error('Failed to load proxies from cache', { error });
|
logger.error('Failed to load proxies from cache', { error });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the singleton instance
|
||||||
|
*/
|
||||||
|
static async initialize(): Promise<void> {
|
||||||
|
if (!ProxyManager.instance) {
|
||||||
|
ProxyManager.instance = new ProxyManager();
|
||||||
|
await ProxyManager.instance.initializeInternal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Singleton instance for easy import
|
/**
|
||||||
export const proxyManager = new ProxyManager();
|
* Get the singleton instance (must be initialized first)
|
||||||
|
*/
|
||||||
|
static getInstance(): ProxyManager {
|
||||||
|
if (!ProxyManager.instance) {
|
||||||
|
throw new Error('ProxyManager not initialized. Call ProxyManager.initialize() first.');
|
||||||
|
}
|
||||||
|
return ProxyManager.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the singleton instance (for testing)
|
||||||
|
*/
|
||||||
|
static reset(): void {
|
||||||
|
ProxyManager.instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the class as default
|
||||||
|
export default ProxyManager;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue