RetryKit is a package that implements a mechanism for retrying work based on strategies and outputs.

What's New





RetryKit is a tiny package that implements a flexible mechanism for retrying work based on strategies and outputs (and when using e.g. NSOperation is overkill).

It has been written with two principles in mind: simplicity and elegance.


RetryKit is distributed using the Swift Package Manager. To install it into a project, add it as a dependency within your Package.swift manifest:

let package = Package(
    dependencies: [
        .package(url: "", from: "0.1.0")

Then import RetryKit wherever you’d like to use it:

import RetryKit

It's that simple! 🎉


Using RetryKit is easy.

Work is being encapsulated in Task objects. These objects don't do anything else than abstracting any work, providing an output validation closure and keeping track of the number of times they have been retried. They're really simple but allow for much flexibility, as reflected by their initializer:

let task = Task<Result<String, Error>>(maximumAttempts: 5, work: { output in
    // perform any synchronous or asynchronous work
    // and execute the output closure with your result
}, outputValidation: { output in
    // perform any validation and return a flag whether a retry should be performed
    switch output {
        case .success:
            return false
        case .failure:
            return true

The output validation closure is being called during the retry process with the value of the produced output and allows for customizing the conditions under which a an attempt is being made, case-by-case. Therefore, it allows for simple but also pretty complex conditions.

Task objects are being dispatched by a Retrier object. Retrier objects are equally simple. They do have a single responsibility: dispatching tasks when appropriate (as decided by the output validation closure and the strategy.


RetryKit ships with three built-in different strategies for retrying: immediate, after(delay: TimeInterval),.custom((Int) -> TimeInterval). These strategies should cover almost every scenario.


.immediate is the easiest from all of them. All work is being retried immediately without any delay in between. You might want to use this one when many repetitive retries is not a concern.

after(delay: TimeInterval)

after(delay: TimeInterval) does basically what you would expect by reading its interface. Work is being retried after a constant delay in between attempts.

.custom((Int) -> TimeInterval)

.custom((Int) -> TimeInterval) allows for most customization out of these three. The delay between attempts is being provided/calculcated by yourself using the number of retries that have happened so far.

A custom strategy is often most useful when you care about adding some randomness to it and allows for using an exponential backoff delay between attempts.


  • Swift Tools 5.3.0
View More Packages from this Author


  • None
Last updated: Wed May 24 2023 10:07:04 GMT-0500 (GMT-05:00)