Skip to content

About

A Kotlin exploration of retry architecture inspired by Android WorkManager, separating failure classification from retry policy.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

16 Commits

Folders and files

Repository files navigation

Retry Task Engine

An exploration of separating failure classification from retry policy.

Motivation

While exploring Android WorkManager, I noticed a common implementation pattern.

A typical worker catches exceptions and immediately decides whether the work should be retried or considered a permanent failure.

class UploadWorker(...) : Worker(...) {

    override fun doWork(): Result {
        return try {
            api.upload()
            Result.success()
        } catch (e: IOException) {
            Result.retry()
        } catch (e: AuthenticationException) {
            Result.failure()
        }
    }
}

In this example, the worker is responsible for two separate concerns:

  • Classifying what happened (for example, a network failure or an authentication failure).
  • Deciding what the retry system should do (Result.retry() or Result.failure()).

For many applications, this approach works well, and WorkManager provides an excellent API for implementing it.

But as systems grow, maintaining consistent retry logic across multiple workers becomes increasingly difficult.

Rather than proposing a replacement for WorkManager, this repository explores the following design question:

Should failure classification be separated from retry policy?

The architecture is grounded in a simple principle:

Tasks should describe failures. Retry systems should interpret them.

Separating failure classification from retry policy allows each responsibility to evolve independently.

Architecture Overview

The retry engine separates three distinct responsibilities:

  • Tasks perform work and communicate the outcome.
  • Failure types describe what happened.
  • Retry policies decide whether the work should be retried.

By separating these responsibilities, tasks focus solely on reporting results while retry policy remains responsible for making retry decisions.

           +------------------+
           |       Task       |
           +------------------+
                     │
                     ▼
                TaskResult
                     │
          ┌──────────┴──────────┐
          │                     │
          ▼                     ▼
      Success        Failure(FailureType)
                                │
                                ▼
                         RetryPolicy
                                │
                                ▼
                         Retry Decision

Task

A task is responsible for completing a unit of work and communicating the result—it does not decide whether another attempt should be made.

TaskResult

TaskResult defines the contract between a task and the retry engine.

A task can either:

  • Complete successfully.
  • Report a failure by returning a FailureType.

Applications express failures using domain-specific representations such as exceptions, HTTP status codes, and SDK-specific error types. Because the retry engine cannot interpret these representations directly, failures must first be translated into a FailureType.

FailureType

FailureType is the semantic vocabulary understood by the retry engine.

By expressing failures in terms of FailureType, tasks communicate retry-relevant semantics while keeping the retry engine independent of application-specific failures.

Examples include:

  • NetworkUnavailable
  • AuthenticationExpired
  • RateLimited
  • ServerOverloaded

The translation boundary that makes this separation possible is introduced later.

RetryPolicy

RetryPolicy interprets failure semantics and determines whether a retry is warranted.

Because these decisions are centralized, retry behavior remains consistent across tasks. Its modular design allows it to be updated or extended independently of the rest of the architecture.

Tasks describe failures. RetryPolicy determines how failures are handled.

What allows these responsibilities to remain independent while still working together?

Failure Classification

Architecture

FailureClassifier forms the translation boundary between tasks and RetryPolicy, translating domain-specific failures into terms the retry engine can understand. Those terms are represented by FailureType, the semantic vocabulary used by the retry engine.

Domain Failure
(IOException, HTTP 429, SDK Exception, ...)
        │
        ▼
FailureClassifier
        │
        ▼
FailureType
(NetworkUnavailable, RateLimited, ...)
        │
        ▼
RetryPolicy

Interface

The FailureClassifier interface abstracts away application-specific failure details while exposing a classification contract.

interface FailureClassifier {
    fun classify(throwable: Throwable): FailureType
}

Its responsibility is straightforward: accept a domain-specific failure and return the corresponding FailureType.

By using an interface rather than a concrete implementation, the retry engine remains independent of how failures are classified.

This separation makes it possible to explore different classification strategies without changing the retry engine.

Two implementations were explored:

  • MappingFailureClassifier — a simple exception-to-FailureType mapping.
  • RuleBasedFailureClassifier — a flexible rule-based approach for expressing more complex classification logic.

The complete design exploration of these implementations—including their motivation, tradeoffs, validation, and lessons learned—is documented in classifier/README.md.


Throughout this exploration, one architectural principle remained constant:

Tasks communicate facts. Policies make decisions.

By introducing a dedicated failure classification boundary, retry policy remains focused on interpreting failure semantics, while applications remain free to communicate failures in whatever form best fits their domain.

About

A Kotlin exploration of retry architecture inspired by Android WorkManager, separating failure classification from retry policy.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages