Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

space-code/typhoon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

85 Commits

A powerful retry policy service for Swift

typhoon

License Swift Compatibility Platform Compatibility CI

Description

Typhoon is a modern, lightweight Swift framework that provides elegant and robust retry policies for asynchronous operations. Built with Swift's async/await concurrency model, it helps you handle transient failures gracefully with configurable retry strategies.

Features

✨ Multiple Retry Strategies - Constant, exponential, and exponential with jitter
⚑ Async/Await Native - Built for modern Swift concurrency
🎯 Type-Safe - Leverages Swift's type system for compile-time safety
πŸ”§ Configurable - Flexible retry parameters for any use case
πŸ“± Cross-Platform - Works on iOS, macOS, tvOS, watchOS, and visionOS
⚑ Lightweight - Minimal footprint with zero dependencies
πŸ§ͺ Well Tested - Comprehensive test coverage

Table of Contents

Requirements

Platform Minimum Version
iOS 13.0+
macOS 10.15+
tvOS 13.0+
watchOS 6.0+
visionOS 1.0+
Xcode 15.3+
Swift 5.10+

Installation

Swift Package Manager

Add the following dependency to your Package.swift:

dependencies: [
 .package(url: "https://github.com/space-code/typhoon.git", from: "1.4.0")
]

Or add it through Xcode:

  1. File > Add Package Dependencies
  2. Enter package URL: https://github.com/space-code/typhoon.git
  3. Select version requirements

Quick Start

import Typhoon
let retryService = RetryPolicyService(
 strategy: .constant(retry: 3, duration: .seconds(1))
)
do {
 let result = try await retryService.retry {
 try await fetchDataFromAPI()
 }
 print("βœ… Success: \(result)")
} catch {
 print("❌ Failed after retries: \(error)")
}

Usage

Retry Strategies

Typhoon provides three powerful retry strategies to handle different failure scenarios:

/// A retry strategy with a constant number of attempts and fixed duration between retries.
case constant(retry: Int, duration: DispatchTimeInterval)
/// A retry strategy with an exponential increase in duration between retries.
case exponential(retry: Int, multiplier: Double = 2.0, duration: DispatchTimeInterval)
/// A retry strategy with exponential increase in duration between retries and added jitter.
case exponentialWithJitter(
 retry: Int, 
 jitterFactor: Double = 0.1, 
 maxInterval: DispatchTimeInterval? = .seconds(60), 
 multiplier: Double = 2.0, 
 duration: DispatchTimeInterval
)

Constant Strategy

Best for scenarios where you want predictable, fixed delays between retries:

import Typhoon
// Retry up to 5 times with 2 seconds between each attempt
let service = RetryPolicyService(
 strategy: .constant(retry: 4, duration: .seconds(2))
)
do {
 let data = try await service.retry {
 try await URLSession.shared.data(from: url)
 }
} catch {
 print("Failed after 5 attempts")
}

Retry Timeline:

  • Attempt 1: Immediate
  • Attempt 2: After 2 seconds
  • Attempt 3: After 2 seconds
  • Attempt 4: After 2 seconds
  • Attempt 5: After 2 seconds

Exponential Strategy

Ideal for avoiding overwhelming a failing service by progressively increasing wait times:

import Typhoon
// Retry up to 4 times with exponentially increasing delays
let service = RetryPolicyService(
 strategy: .exponential(
 retry: 3,
 multiplier: 2.0,
 duration: .seconds(1)
 )
)
do {
 let response = try await service.retry {
 try await performNetworkRequest()
 }
} catch {
 print("Request failed after exponential backoff")
}

Retry Timeline:

  • Attempt 1: Immediate
  • Attempt 2: After 1 second (1 ×ば぀ 20)
  • Attempt 3: After 2 seconds (1 ×ば぀ 21)
  • Attempt 4: After 4 seconds (1 ×ば぀ 22)

Exponential with Jitter Strategy

The most sophisticated strategy, adding randomization to prevent thundering herd problems:

import Typhoon
// Retry with exponential backoff, jitter, and maximum interval cap
let service = RetryPolicyService(
 strategy: .exponentialWithJitter(
 retry: 5,
 jitterFactor: 0.2, // Add Β±20% randomization
 maxInterval: .seconds(30), // Cap at 30 seconds
 multiplier: 2.0,
 duration: .seconds(1)
 )
)
do {
 let result = try await service.retry {
 try await connectToDatabase()
 }
} catch {
 print("Connection failed after sophisticated retry attempts")
}

Benefits of Jitter:

  • Prevents multiple clients from retrying simultaneously
  • Reduces load spikes on recovering services
  • Improves overall system resilience

Common Use Cases

Network Requests

import Typhoon
class APIClient {
 private let retryService = RetryPolicyService(
 strategy: .exponential(retry: 3, duration: .milliseconds(500))
 )
 
 func fetchUser(id: String) async throws -> User {
 try await retryService.retry {
 let (data, _) = try await URLSession.shared.data(
 from: URL(string: "https://api.example.com/users/\(id)")!
 )
 return try JSONDecoder().decode(User.self, from: data)
 }
 }
}

Database Operations

import Typhoon
class DatabaseManager {
 private let retryService = RetryPolicyService(
 strategy: .exponentialWithJitter(
 retry: 5,
 jitterFactor: 0.15,
 maxInterval: .seconds(60),
 duration: .seconds(1)
 )
 )
 
 func saveRecord(_ record: Record) async throws {
 try await retryService.retry {
 try await database.insert(record)
 }
 }
}

File Operations

import Typhoon
class FileService {
 private let retryService = RetryPolicyService(
 strategy: .constant(retry: 3, duration: .milliseconds(100))
 )
 
 func writeFile(data: Data, to path: String) async throws {
 try await retryService.retry {
 try data.write(to: URL(fileURLWithPath: path))
 }
 }
}

Third-Party Service Integration

import Typhoon
class PaymentService {
 private let retryService = RetryPolicyService(
 strategy: .exponential(
 retry: 4,
 multiplier: 1.5,
 duration: .seconds(2)
 )
 )
 
 func processPayment(amount: Decimal) async throws -> PaymentResult {
 try await retryService.retry {
 try await paymentGateway.charge(amount: amount)
 }
 }
}

Communication

Documentation

Comprehensive documentation is available: Typhoon Documentation

Contributing

We love contributions! Please feel free to help out with this project. If you see something that could be made better or want a new feature, open up an issue or send a Pull Request.

Development Setup

Bootstrap the development environment:

mise install

Author

Nikita Vasilev

License

Typhoon is released under the MIT license. See LICENSE for details.


⬆ back to top

Made with ❀️ by space-code

Packages

No packages published

Contributors 3

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /