RetryPolicy

com.softinio.verdict4s.algebra.RetryPolicy
See theRetryPolicy companion object
final case class RetryPolicy

How to back off and retry when the service asks you to.

The API documents 429 and 529 with an explicit instruction to retry with exponential backoff, and the official SDKs do so by default; RetryPolicy.default matches their settings.

Everything here is pure. delayFor takes the jitter sample as an argument rather than drawing one, which means the whole schedule is a function of its inputs and can be tested exactly, with no clock, no random source, and no mocking library. Drawing the sample is the client's job.

Value parameters

backoffInitial

the first delay, doubled each attempt

backoffMax

ceiling for the doubling

jitter

0 to 1; the fraction by which a delay may vary, so that many clients retrying at once spread out instead of arriving together

maxRetries

attempts after the first; 0 disables retrying

respectRetryAfter

whether a Retry-After header wins when it asks for longer than the computed backoff

retryableStatuses

which statuses are worth retrying

totalTimeout

ceiling on the whole call, retries included. Exceeding it fails the call with a com.softinio.verdict4s.Verdict4sError.Transport. A delay, from the header or the backoff, of at least the time left in it ends the retries instead, with the server's own error, since that wait could only end in a timeout.

Attributes

Companion
object
Graph
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all

Members list

Value members

Concrete methods

def delayFor(attempt: Int, retryAfter: Option[FiniteDuration], jitterSample: Double): Option[FiniteDuration]

How long to wait before attempt, or None when retries are exhausted.

How long to wait before attempt, or None when retries are exhausted.

The delay is the jittered backoff, or the server's Retry-After when it is honoured and asks for longer. Also None when that delay is at least totalTimeout, by the same rule whether it came from the header or the backoff: the call could never outlive that wait, so sleeping through it would only trade the server's error for a timeout. Giving up returns the server's own error, with its retryAfter, at once.

This is pure, so it can only compare against the whole budget. The client applies the same rule to the budget left: it also gives up when the delay is at least totalTimeout minus the time the call has already taken.

Value parameters

attempt

1-based: the attempt about to be made, so the first retry is attempt 1

jitterSample

a value in [0, 1) supplied by the caller

retryAfter

the server's own request, if it sent one

Attributes

def retriesStatus(status: Int): Boolean

Whether this status is one this policy retries.

Whether this status is one this policy retries.

Attributes

def schedule(jitterSamples: LazyList[Double]): List[FiniteDuration]

The whole schedule, for documentation and one-assertion tests.

The whole schedule, for documentation and one-assertion tests.

Attributes

Inherited methods

Attributes

Inherited from:
Product

Attributes

Inherited from:
Product