Skip to content

Commit

Permalink
Set upper bound on device token sleep interval after HTTP errors (#216)
Browse files Browse the repository at this point in the history
Section 3.5 of RFC 8628 requires a polling backoff in response to HTTP
connection timeouts. However, doubling the interval each time can
quickly lead to an effectively infinite backoff, which is undesirable.

This change adds a configurable max backoff interval to use in cases
of HTTP client errors (which may be due to a variety of causes,
including connection timeouts). The default is 10 seconds (twice the
default polling interval of 5 seconds defined in RFC 8628), which
attempts to strike a balance between user experience and server load.

Fixes #214.
  • Loading branch information
LorenzoLeonardo committed May 16, 2023
1 parent 00fa30b commit 1472310
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,7 @@ where
token_url: self.token_url.as_ref(),
dev_auth_resp: auth_response,
time_fn: Arc::new(Utc::now),
max_backoff_interval: None,
_phantom: PhantomData,
}
}
Expand Down Expand Up @@ -2264,6 +2265,7 @@ where
token_url: Option<&'a TokenUrl>,
dev_auth_resp: &'a DeviceAuthorizationResponse<EF>,
time_fn: Arc<dyn Fn() -> DateTime<Utc> + 'b + Send + Sync>,
max_backoff_interval: Option<Duration>,
_phantom: PhantomData<(TR, TT, EF)>,
}

Expand Down Expand Up @@ -2310,6 +2312,15 @@ where
self
}

///
/// Sets the upper limit of the interval during polling of access token
/// just incase there is a return error from the http_client
///
pub fn set_max_backoff_interval(mut self, interval: Duration) -> Self {
self.max_backoff_interval = Some(interval);
self
}

///
/// Synchronously polls the authorization server for a response, waiting
/// using a user defined sleep function.
Expand Down Expand Up @@ -2433,8 +2444,16 @@ where
let http_response = match res {
Ok(inner) => inner,
Err(_) => {
// Try and double the current interval. If that fails, just use the current one.
let new_interval = current_interval.checked_mul(2).unwrap_or(current_interval);
// RFC 8628 requires a backoff in cases of connection timeout, but we can't
// distinguish between connection timeouts and other HTTP client request errors
// here. Set a maximum backoff so that the client doesn't effectively backoff
// infinitely when there are network issues unrelated to server load.
const DEFAULT_MAX_BACKOFF_INTERVAL: Duration = Duration::from_secs(10);
let new_interval = std::cmp::min(
current_interval.checked_mul(2).unwrap_or(current_interval),
self.max_backoff_interval
.unwrap_or(DEFAULT_MAX_BACKOFF_INTERVAL),
);
return DeviceAccessTokenPollResult::ContinueWithNewPollInterval(new_interval);
}
};
Expand Down

0 comments on commit 1472310

Please sign in to comment.