@@ -49,6 +49,8 @@ import org.http4s.Method
4949import org .http4s .Request
5050import org .http4s .Uri
5151import org .http4s .client .Client
52+ import org .http4s .client .middleware .Retry
53+ import org .http4s .client .middleware .RetryPolicy
5254import org .typelevel .ci .*
5355import scala .annotation .nowarn
5456import scala .concurrent .duration .*
@@ -147,8 +149,14 @@ object CredentialsProvider {
147149 * active credentials available, it will continue to return the
148150 * active credentials while trying to refresh, until the
149151 * credentials expire in 1 minute or less.
152+ *
153+ * There is a retry policy in place to avoid intermittent
154+ * issues when requesting credentials.
150155 */
151156 def containerEndpoint [F [_]: Async ](client : Client [F ]): Resource [F , CredentialsProvider [F ]] = {
157+ val retryClient : Client [F ] =
158+ Retry (RetryPolicy (RetryPolicy .exponentialBackoff(maxWait = 3 .seconds, maxRetry = 5 )))(client)
159+
152160 def credentialsUri : F [Uri ] =
153161 for {
154162 path <- ContainerCredentialsRelativeUri [F ].read
@@ -173,7 +181,7 @@ object CredentialsProvider {
173181 .map(_.trim)
174182 .map(Header .Raw (ci " Authorization " , _))
175183
176- def requestCredentials ( retryAttempts : Int = 0 , maxRetries : Int = 5 ) : F [ExpiringCredentials ] =
184+ def requestCredentials : F [ExpiringCredentials ] =
177185 for {
178186 uri <- credentialsUri
179187 authorizationTokenFile <- ContainerAuthorizationTokenFile [F ].read
@@ -182,10 +190,7 @@ object CredentialsProvider {
182190 authorizationToken = ContainerAuthorizationToken [F ].read
183191 authorization <- authorizationTokenFile.getOrElse(authorizationToken)
184192 request = Request [F ](Method .GET , uri).withHeaders(authorization)
185- expiring <- client.expect[ExpiringCredentials ](request).recoverWith {
186- case _ if retryAttempts < maxRetries =>
187- requestCredentials(retryAttempts + 1 )
188- }
193+ expiring <- retryClient.expect[ExpiringCredentials ](request)
189194 } yield expiring
190195
191196 def sleepUntilRefresh (ref : Ref [F , Either [Throwable , ExpiringCredentials ]]): F [Unit ] =
@@ -203,7 +208,7 @@ object CredentialsProvider {
203208 def refreshCredentials (ref : Ref [F , Either [Throwable , ExpiringCredentials ]]): F [Unit ] =
204209 for {
205210 _ <- sleepUntilRefresh(ref)
206- credentials <- requestCredentials() .attempt
211+ credentials <- requestCredentials.attempt
207212 now <- Async [F ].realTime.map(d => Instant .EPOCH .plusNanos(d.toNanos))
208213 _ <- ref.update {
209214 case right @ Right (existing) if credentials.isLeft && existing.isFresh(now) => right
@@ -212,7 +217,7 @@ object CredentialsProvider {
212217 } yield ()
213218
214219 for {
215- credentials <- requestCredentials() .attempt.toResource
220+ credentials <- requestCredentials.attempt.toResource
216221 ref <- Ref [F ].of(credentials).toResource
217222 _ <- refreshCredentials(ref).foreverM[Unit ].background
218223 } yield new CredentialsProvider [F ] {
0 commit comments