@@ -681,6 +681,8 @@ void IdTokenRefreshThread::Initialize(AuthData* auth_data) {
681681 thread_ = firebase::Thread (
682682 [](IdTokenRefreshThread* refresh_thread) {
683683 Auth* auth = refresh_thread->auth ;
684+ int retry_backoff_ms = kMinRetryBackoffMs ;
685+
684686 while (!refresh_thread->is_shutting_down ()) {
685687 // Note: Make sure to always make future_impl.mutex the innermost
686688 // lock, to prevent deadlocks!
@@ -714,10 +716,20 @@ void IdTokenRefreshThread::Initialize(AuthData* auth_data) {
714716 // is completed.
715717 future_sem.Wait ();
716718
717- // If token refresh failed (e.g. network outage), wait before retrying
718- // to prevent a 0ms tight retry loop and high CPU usage.
719- if (future.error () != 0 && !refresh_thread->is_shutting_down ()) {
720- refresh_thread->wakeup_sem_ .TimedWait (kMsPerTokenRefreshFailedRetry );
719+ if (future.error () != 0 ) {
720+ // Token refresh failed (e.g. network outage). Wait with exponential backoff
721+ // to prevent tight retry loops and avoid overloading backend servers upon reconnect.
722+ if (!refresh_thread->is_shutting_down ()) {
723+ int jitter_ms = rand () % 1000 ;
724+ int wait_time_ms = retry_backoff_ms + jitter_ms;
725+ // Double backoff for consecutive failures up to max 30 minutes.
726+ retry_backoff_ms = std::min (kMaxRetryBackoffMs , retry_backoff_ms * 2 );
727+ refresh_thread->wakeup_sem_ .TimedWait (wait_time_ms);
728+ }
729+ continue ;
730+ } else {
731+ // Refresh succeeded! Reset backoff to minimum interval.
732+ retry_backoff_ms = kMinRetryBackoffMs ;
721733 }
722734 } else {
723735 auth->auth_data_ ->future_impl .mutex ().Release ();
0 commit comments