@@ -112,6 +112,8 @@ class Doc2Vec {
112112 const lastRunDate = await DatabaseManager . getLastRunDate ( dbConnection , repo , `${ startDate } T00:00:00Z` , logger ) ;
113113
114114 const fetchWithRetry = async ( url : string , params = { } , retries = 5 , delay = 5000 ) : Promise < any > => {
115+ const retryableCodes = [ 'ECONNRESET' , 'ETIMEDOUT' , 'ECONNREFUSED' , 'ENOTFOUND' , 'EAI_AGAIN' , 'EPIPE' , 'EHOSTUNREACH' ] ;
116+
115117 for ( let attempt = 0 ; attempt < retries ; attempt ++ ) {
116118 try {
117119 const response = await axios . get ( url , {
@@ -120,15 +122,26 @@ class Doc2Vec {
120122 Accept : 'application/vnd.github.v3+json' ,
121123 } ,
122124 params,
125+ timeout : 30000 , // 30 second timeout
123126 } ) ;
124127 return response . data ;
125128 } catch ( error : any ) {
126- if ( error . response && error . response . status === 403 ) {
129+ const isLastAttempt = attempt === retries - 1 ;
130+ const errorCode = error . code || ( error . cause && error . cause . code ) ;
131+ const isRetryableNetworkError = retryableCodes . includes ( errorCode ) ;
132+ const isRateLimitError = error . response && error . response . status === 403 ;
133+ const isServerError = error . response && error . response . status >= 500 ;
134+
135+ if ( isRateLimitError ) {
127136 const resetTime = error . response . headers [ 'x-ratelimit-reset' ] ;
128137 const currentTime = Math . floor ( Date . now ( ) / 1000 ) ;
129138 const waitTime = resetTime ? ( resetTime - currentTime ) * 1000 : delay * 2 ;
130- logger . warn ( `GitHub rate limit exceeded. Waiting ${ waitTime / 1000 } s` ) ;
139+ logger . warn ( `GitHub rate limit exceeded. Waiting ${ waitTime / 1000 } s (attempt ${ attempt + 1 } / ${ retries } ) ` ) ;
131140 await new Promise ( res => setTimeout ( res , waitTime ) ) ;
141+ } else if ( ( isRetryableNetworkError || isServerError ) && ! isLastAttempt ) {
142+ const backoffTime = delay * Math . pow ( 2 , attempt ) ; // Exponential backoff
143+ logger . warn ( `Network error (${ errorCode || error . message } ). Retrying in ${ backoffTime / 1000 } s (attempt ${ attempt + 1 } /${ retries } )` ) ;
144+ await new Promise ( res => setTimeout ( res , backoffTime ) ) ;
132145 } else {
133146 logger . error ( `GitHub fetch failed: ${ error . message } ` ) ;
134147 throw error ;
0 commit comments