@@ -56,6 +56,7 @@ export class OAuth2ProviderManager {
5656 private providers : Map < string , OAuth2ClientWithConfig > = new Map ( )
5757 private providerStatus : Map < string , ProviderStatus > = new Map ( )
5858 private healthCheckInterval : NodeJS . Timeout | null = null
59+ private retryInterval : NodeJS . Timeout | null = null
5960 private factory : OAuth2ProviderFactory
6061 private obpClientService : OBPClientService
6162 private initialized : boolean = false
@@ -187,6 +188,12 @@ export class OAuth2ProviderManager {
187188 console . error (
188189 'OAuth2ProviderManager: Users will not be able to log in until at least one provider is available'
189190 )
191+ console . log ( 'OAuth2ProviderManager: Will retry initialization every 30 seconds...' )
192+ }
193+
194+ // Start retry interval for failed providers
195+ if ( successCount < wellKnownUris . length ) {
196+ this . startRetryInterval ( )
190197 }
191198
192199 return this . initialized
@@ -223,6 +230,87 @@ export class OAuth2ProviderManager {
223230 }
224231 }
225232
233+ /**
234+ * Start periodic retry for failed providers
235+ *
236+ * @param intervalMs - Retry interval in milliseconds (default: 30000 = 30 seconds)
237+ */
238+ startRetryInterval ( intervalMs : number = 30000 ) : void {
239+ if ( this . retryInterval ) {
240+ console . log ( 'OAuth2ProviderManager: Retry interval already running' )
241+ return
242+ }
243+
244+ console . log ( `OAuth2ProviderManager: Starting retry interval (every ${ intervalMs / 1000 } s)` )
245+
246+ this . retryInterval = setInterval ( async ( ) => {
247+ await this . retryFailedProviders ( )
248+ } , intervalMs )
249+ }
250+
251+ /**
252+ * Stop periodic retry interval
253+ */
254+ stopRetryInterval ( ) : void {
255+ if ( this . retryInterval ) {
256+ clearInterval ( this . retryInterval )
257+ this . retryInterval = null
258+ console . log ( 'OAuth2ProviderManager: Retry interval stopped' )
259+ }
260+ }
261+
262+ /**
263+ * Retry all failed providers
264+ */
265+ private async retryFailedProviders ( ) : Promise < void > {
266+ const failedProviders : string [ ] = [ ]
267+
268+ this . providerStatus . forEach ( ( status , name ) => {
269+ if ( ! status . available ) {
270+ failedProviders . push ( name )
271+ }
272+ } )
273+
274+ // Also check if we have no providers at all (initial fetch may have failed)
275+ if ( this . providerStatus . size === 0 ) {
276+ console . log (
277+ 'OAuth2ProviderManager: No providers initialized yet, attempting full initialization...'
278+ )
279+
280+ // Temporarily stop retry to prevent duplicate calls
281+ this . stopRetryInterval ( )
282+
283+ const success = await this . initializeProviders ( )
284+ if ( ! success ) {
285+ // Restart retry if initialization failed
286+ this . startRetryInterval ( )
287+ }
288+ return
289+ }
290+
291+ if ( failedProviders . length === 0 ) {
292+ console . log ( 'OAuth2ProviderManager: All providers healthy, stopping retry interval' )
293+ this . stopRetryInterval ( )
294+ return
295+ }
296+
297+ console . log ( `OAuth2ProviderManager: Retrying ${ failedProviders . length } failed provider(s)...` )
298+
299+ for ( const providerName of failedProviders ) {
300+ const success = await this . retryProvider ( providerName )
301+ if ( success ) {
302+ console . log ( `OAuth2ProviderManager: Successfully recovered provider: ${ providerName } ` )
303+ }
304+ }
305+
306+ // Check if all providers are now healthy
307+ const stillFailed = Array . from ( this . providerStatus . values ( ) ) . filter ( ( s ) => ! s . available )
308+ if ( stillFailed . length === 0 ) {
309+ console . log ( 'OAuth2ProviderManager: All providers recovered, stopping retry interval' )
310+ this . stopRetryInterval ( )
311+ }
312+ }
313+
226314 /**
227315 * Perform health check on all providers
228316 *
0 commit comments