SwiftUI Circuit Breakers & Network Resilience Patterns (Prevent Cascading Failures)

Published: (March 7, 2026 at 03:48 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

Most apps call APIs like this:

try await api.fetchUser()

That works… until the server starts failing. Then your app may:

  • retry immediately
  • send hundreds of failing requests
  • drain battery
  • overload the backend
  • slow down the UI
  • worsen the outage

This is called a cascading failure. A production app needs protection mechanisms.

🧠 The Core Principle

When a system is failing, stop making it worse. Instead of retrying endlessly, the system must detect failures and pause requests.

🧱 1. What Is a Circuit Breaker?

A circuit breaker prevents repeated calls to a failing service. It has three states:

Closed → Normal operation
Open → Requests blocked
Half-Open → Testing recovery

Flow

Requests Fail
→ Circuit Opens
→ Requests Blocked
→ Recovery Test
→ Circuit Closes

🔌 2. Define Circuit States

enum CircuitState {
    case closed
    case open(until: Date)
    case halfOpen
}
  • Closed → requests allowed
  • Open → requests blocked temporarily
  • Half‑Open → allow limited requests to test recovery

🧬 3. Basic Circuit Breaker Implementation

final class CircuitBreaker {
    private(set) var state: CircuitState = .closed
    private var failureCount = 0
    private let failureThreshold = 5
    private let timeout: TimeInterval = 30

    func recordFailure() {
        failureCount += 1
        if failureCount >= failureThreshold {
            state = .open(until: Date().addingTimeInterval(timeout))
        }
    }

    func recordSuccess() {
        failureCount = 0
        state = .closed
    }
}

Failures accumulate until the circuit opens.

🚦 4. Blocking Requests When Circuit Is Open

Before performing a request:

func canExecute() -> Bool {
    switch state {
    case .closed:
        return true
    case .open(let until):
        return Date() > until
    case .halfOpen:
        return true
    }
}

Usage

guard breaker.canExecute() else {
    throw NetworkError.circuitOpen
}

This protects the backend.

🔄 5. Transition to Half‑Open

When the timeout expires:

case .open(let until):
    if Date() > until {
        state = .halfOpen
        return true
    }

Only a small number of requests should test recovery. If they succeed → close the circuit; if they fail → reopen.

🔋 6. Why Mobile Apps Need Circuit Breakers

Mobile networks are unstable. Common failure scenarios include:

  • server outage
  • DNS issues
  • TLS failures
  • rate limiting
  • cellular packet loss

Without circuit breakers, your app may:

  • spam the backend
  • drain battery rapidly
  • amplify the outage

Circuit breakers prevent this.

🧱 7. Integrating with API Clients

Wrap network calls:

func performRequest(_ operation: () async throws -> T) async throws -> T {
    guard breaker.canExecute() else {
        throw NetworkError.circuitOpen
    }

    do {
        let result = try await operation()
        breaker.recordSuccess()
        return result
    } catch {
        breaker.recordFailure()
        throw error
    }
}

This makes resilience automatic.

🌐 8. Combine with Retry Strategies

Circuit breakers work with retries. Example flow:

Request
→ Failure
→ Retry (exponential backoff)
→ Failure threshold reached
→ Circuit opens
→ Requests paused

This prevents retry storms.

🧪 9. Testing Circuit Breakers

Test scenarios:

  • repeated server errors
  • timeout storms
  • network disconnections
  • recovery after outage
  • half‑open transition

Verify that:

  • requests stop during outages
  • requests resume after recovery

⚠️ 10. Common Anti‑Patterns

Avoid:

  • infinite retries
  • retrying immediately after failure
  • ignoring server rate limits
  • retrying while offline
  • not tracking failure counts

These cause backend overload, cascading outages, and battery drain.

🧠 Mental Model

Request
 → Failure Detection
   → Circuit Breaker
     → Pause Requests
       → Recovery Probe
         → Resume Traffic

Not: “Just retry again.”

🚀 Final Thoughts

Circuit breakers give your app:

  • backend protection
  • smarter retry behavior
  • reduced battery usage
  • resilience during outages
  • predictable recovery

They are the difference between a fragile network client and a production‑grade mobile system.

0 views
Back to Blog

Related posts

Read more »

Create AppStore Images with one liner

!Cover image for Create AppStore Images with one linerhttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2...