@@ -13,6 +13,14 @@ const errorTracker = new Map<
1313 }
1414> ( ) ;
1515
16+ // Track rotation state
17+ const rotationState = {
18+ isRotating : false ,
19+ lastRotationStart : 0 ,
20+ rotationAttempts : new Map < string , number > ( ) ,
21+ maxAttempts : 3 ,
22+ } ;
23+
1624const ROTATION_THRESHOLD = 5 ;
1725const ROTATION_COOLDOWN = 60000 ;
1826const STATUS_CODE_WEIGHTS : Record < number , number > = {
@@ -29,8 +37,33 @@ const MIN_OCCURRENCES: Record<number, number> = {
2937 999 : 2 , // Need couple timeouts
3038} ;
3139
40+ // Dynamic backoff calculation based on recent errors and rotation history
41+ function calculateBackoff ( providerKey : string ) : number {
42+ const attempts = rotationState . rotationAttempts . get ( providerKey ) || 0 ;
43+ const baseDelay = 1000 ; // 1 second base
44+ const jitter = Math . random ( ) * 500 ; // Add some randomness
45+ return Math . min ( baseDelay * Math . pow ( 1.5 , attempts ) + jitter , 10000 ) ; // Cap at 10 seconds
46+ }
47+
48+ async function waitForRotation ( providerKey : string ) : Promise < void > {
49+ if ( ! rotationState . isRotating ) return ;
50+
51+ const backoff = calculateBackoff ( providerKey ) ;
52+ await new Promise ( ( resolve ) => setTimeout ( resolve , backoff ) ) ;
53+
54+ // Increment attempt counter
55+ const attempts = ( rotationState . rotationAttempts . get ( providerKey ) || 0 ) + 1 ;
56+ rotationState . rotationAttempts . set ( providerKey , attempts ) ;
57+
58+ // If we've waited too long, reset rotation state
59+ if ( Date . now ( ) - rotationState . lastRotationStart > 30000 ) {
60+ rotationState . isRotating = false ;
61+ rotationState . rotationAttempts . clear ( ) ;
62+ }
63+ }
64+
3265function shouldRotateIP ( errorState : { count : number ; lastRotation : number ; statusCodes : Map < number , number > } ) : boolean {
33- if ( Date . now ( ) - errorState . lastRotation < ROTATION_COOLDOWN ) {
66+ if ( Date . now ( ) - errorState . lastRotation < ROTATION_COOLDOWN || rotationState . isRotating ) {
3467 return false ;
3568 }
3669
@@ -69,12 +102,17 @@ async function makeRequest(url: string, options: RequestInit, timeout: number =
69102export async function customRequest ( url : string , options : IRequestConfig = { } ) : Promise < Response | null > {
70103 const { isChecking, proxy, useGoogleTranslate, timeout, providerType, providerId, maxRetries, validateResponse } = options ;
71104 const retryAttempts = isChecking ? 1 : maxRetries || 3 ;
105+ const providerKey = `${ providerType } -${ providerId } ` ;
72106
73107 // Try different request strategies in sequence
74108 for ( let attempt = 1 ; attempt <= retryAttempts ; attempt ++ ) {
109+ // Wait if IP rotation is in progress
110+ if ( rotationState . isRotating ) {
111+ await waitForRotation ( providerKey ) ;
112+ }
113+
75114 // 1. Try WireGuard proxy first if enabled
76115 if ( ! useGoogleTranslate && ! isChecking && env . USE_WIREGUARD ) {
77- const providerKey = `${ providerType } -${ providerId } ` ;
78116 const errorState = errorTracker . get ( providerKey ) || {
79117 count : 0 ,
80118 lastRotation : 0 ,
@@ -83,16 +121,25 @@ export async function customRequest(url: string, options: IRequestConfig = {}):
83121
84122 if ( shouldRotateIP ( errorState ) ) {
85123 try {
124+ rotationState . isRotating = true ;
125+ rotationState . lastRotationStart = Date . now ( ) ;
126+
86127 await wireguardProxyManager . rotate ( ) ;
128+
87129 errorTracker . set ( providerKey , {
88130 count : 0 ,
89131 lastRotation : Date . now ( ) ,
90132 statusCodes : new Map ( ) ,
91133 } ) ;
134+
92135 console . log ( `Rotated IP for provider ${ providerKey } due to error threshold` ) ;
93- await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
136+
137+ // Clear rotation state after successful rotation
138+ rotationState . isRotating = false ;
139+ rotationState . rotationAttempts . delete ( providerKey ) ;
94140 } catch ( error ) {
95141 console . warn ( "Failed to rotate WireGuard IP:" , error ) ;
142+ rotationState . isRotating = false ;
96143 }
97144 }
98145
@@ -165,7 +212,22 @@ export async function customRequest(url: string, options: IRequestConfig = {}):
165212 }
166213 }
167214
168- // If all strategies failed, log warning and return null
169- console . warn ( `All request strategies failed for ${ url } . Provider: ${ providerId } /${ providerType } ` ) ;
215+ // If all strategies failed, update error tracking and return null
216+ if ( providerType && providerId ) {
217+ const errorState = errorTracker . get ( providerKey ) || {
218+ count : 0 ,
219+ lastRotation : 0 ,
220+ statusCodes : new Map ( ) ,
221+ } ;
222+
223+ // Add to error count and track as a 503 error (service unavailable)
224+ const currentCount = errorState . statusCodes . get ( 503 ) || 0 ;
225+ errorState . statusCodes . set ( 503 , currentCount + 1 ) ;
226+ errorState . count ++ ;
227+ errorTracker . set ( providerKey , errorState ) ;
228+
229+ console . warn ( `All request strategies failed for ${ url } . Provider: ${ providerId } /${ providerType } ` ) ;
230+ }
231+
170232 return null ;
171233}
0 commit comments