@@ -56,6 +56,7 @@ export class CredentialManager implements Disposable {
5656 private negotiator : Negotiator ;
5757 private _refreshInFlight = new Map < string , Promise < void > > ( ) ;
5858 private mutex = new Mutex ( ) ;
59+ private _failedRefreshCache = new Map < string , { attemptsCount : number ; lastAttemptAt : Date } > ( ) ;
5960
6061 constructor (
6162 context : ExtensionContext ,
@@ -393,7 +394,10 @@ export class CredentialManager implements Disposable {
393394
394395 if ( credentials . expirationDate ) {
395396 const diff = credentials . expirationDate - Date . now ( ) ;
396- Logger . debug ( `${ Math . floor ( diff / 1000 ) } seconds remaining for auth token.` ) ;
397+ Logger . debug (
398+ `${ Math . floor ( diff / 1000 ) } seconds remaining for ${ site . name } refresh token. ${ diff > GRACE_PERIOD ? 'No refresh needed yet.' : 'refreshing...' } ` ,
399+ ) ;
400+
397401 if ( diff > GRACE_PERIOD ) {
398402 return credentials ; // no need to refresh, we have enough time left
399403 }
@@ -552,6 +556,17 @@ export class CredentialManager implements Disposable {
552556 if ( ! isOAuthInfo ( credentials ) ) {
553557 return undefined ;
554558 }
559+
560+ const failedRefresh = this . _failedRefreshCache . get ( site . credentialId ) ;
561+ if ( failedRefresh ) {
562+ const RETRY_DELAY = 5 * Time . MINUTES ;
563+ // if we already had multiple failed attempts recently, don't try again yet until enough time has passed
564+ if ( failedRefresh . attemptsCount > 5 && Date . now ( ) - failedRefresh . lastAttemptAt . getTime ( ) < RETRY_DELAY ) {
565+ Logger . debug ( `Skipping token refresh for credentialID: ${ site . credentialId } due to previous failures.` ) ;
566+ return undefined ;
567+ }
568+ }
569+
555570 Logger . debug ( `refreshingAccessToken for ${ site . baseApiUrl } credentialID: ${ site . credentialId } ` ) ;
556571
557572 const provider : OAuthProvider | undefined = oauthProviderForSite ( site ) ;
@@ -569,9 +584,16 @@ export class CredentialManager implements Disposable {
569584 }
570585
571586 await this . saveAuthInfo ( site , credentials ) ;
587+ if ( this . _failedRefreshCache . has ( site . credentialId ) ) {
588+ this . _failedRefreshCache . delete ( site . credentialId ) ;
589+ }
572590 Logger . debug ( `Successfully saved refreshed tokens for credentialId: ${ site . credentialId } ` ) ;
573591 } else if ( tokenResponse . shouldInvalidate ) {
574592 credentials . state = AuthInfoState . Invalid ;
593+ this . _failedRefreshCache . set ( site . credentialId , {
594+ attemptsCount : ( this . _failedRefreshCache . get ( site . credentialId ) ?. attemptsCount ?? 0 ) + 1 ,
595+ lastAttemptAt : new Date ( ) ,
596+ } ) ;
575597 await this . saveAuthInfo ( site , credentials ) ;
576598 }
577599 }
0 commit comments