#[non_exhaustive]
pub enum RetryTime {
    Immediate,
    AfterWaiting,
    After(Duration),
    At(Instant),
    Never,
}
Expand description

A description of when an operation may be retried.

Retry times values are contextual.

Note that retrying is necessarily contextual, depending on what exactly we’re talking about retrying.

For an example of how context matters: suppose that we try to build a circuit, and encounter a failure extending to the second hop. If we try to build a circuit through the same path immediately, it’s likely to fail again. But if we try to build a circuit through a different path, then there’s no reason to expect that same kind of error.

Thus, the same inner error condition (“failed to extend to the nth hop”) can indicate either a “Retry after waiting for a while” or “Retry immediately.”

Retry times depend on what we think might change.

Whether retrying will help depends on what we think is likely to change in the near term.

For example, we generally assume an unreachable relay has some likelihood of becoming reachable in the near future, and therefore connecting to such a relay is worth retrying.

On the other hand, we don’t assume that the network is changing wildly over time. Thus, if there is currently no relay that supports delivering traffic to port 23 (telnet), we say that building a request for such a relay is not retriable, even though technically such a relay might appear in the next consensus.

Variants (Non-exhaustive)

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.

Immediate

The operation can be retried immediately, and no delay is needed.

The recipient of this RetryTime variant may retry the operation immediately without waiting.

This case should be used cautiously: it risks making code retry in a loop without delay. It should only be used for error conditions that are necessarily produced via a process that itself introduces a delay. (For example, this case is suitable for errors caused by a remote timeout.)

AfterWaiting

The operation can be retried after a short delay, to prevent overloading the network.

The recipient of this RetryTime variant should delay a short amount of time before retrying. The amount of time to delay should be randomized, and should tend to grow larger the more failures there have been recently for the given operation. (The RetryDelay type from tor-basic-utils is suitable for managing this calculation.)

This case should be used for problems that tend to be “self correcting”, such as remote server failures (the server might come back up).

After(Duration)

The operation can be retried after a particular delay.

The recipient of this RetryTime variant should wait for at least the given duration before retrying the operation.

This case should only be used if there is some reason not to return AfterWaiting: for example, if the implementor is providing their own back-off algorithm instead of using RetryDelay.

(This is a separate variant from At, since the constructor may not have convenient access to (a mocked view of) the current time. If you know that the current time is now, then After(d) is equivalent to At(now + d).)

At(Instant)

The operation can be retried at some particular time in the future.

The recipient of this this RetryTime variant should wait until the current time (as returned by Instant::now or SleepProvider::now as appropriate) is at least this given instant.

This case is appropriate for when we have a failure condition caused by waiting for multiple other timeouts. (For example, if we believe that all our guards are down, then we won’t be able to try getting a guard until the next time guard is scheduled to be marked as retriable.)

Never

Retrying is unlikely to make this operation succeed, unless something else is fixed first.

The recipient of this RetryTime variant should generally give up, and stop retrying the given operation.

We don’t mean “literally” that the operation will never succeed: only that retrying it in the near future without fixing the underlying cause is unlikely to help.

This case is appropriate for issues like misconfiguration, internal errors, and requests for operations that the network doesn’t support.

This case is also appropriate for a problem that is “technically” retriable, but where any resolution is likelier to take days or weeks instead of minutes or hours.

Implementations

Convert this RetryTime in to an absolute time.

Requires that now is the current time, and choose_delay is a function to choose a delay for RetryTime::AfterWaiting.

Convert all the provided items into AbsRetryTime values, and return the earliest one.

Requires that now is the current time, and choose_delay is a function to choose a delay for RetryTime::AfterWaiting.

Differs from items.map(AbsRetryTime::absolute(now, choose_delay)).min() in that it calls choose_delay at most once.

Return the “approximately earliest” item for an iterator of retry times.

This is necessarily an approximation, since we can’t be sure what time will be chosen if the retry is supposed to happen at a random time, and therefore cannot tell whether AfterWaiting comes before or after particular At and After instances.

If you need an exact answer, use earliest_absolute.

A loose-but-total comparison operator, suitable for choosing a retry time when multiple attempts have failed.

If you need an absolute comparison operator, convert to AbsRetryTime first.

Trait Implementations

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

This method tests for self and other values to be equal, and is used by ==. Read more

This method tests for !=.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

Uses borrowed data to replace owned data, usually by cloning. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.