Skip to Content
Course content

128: Circuit Breakers with Akka

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was on a team maintaining a checkout pipeline that relied on a legacy third-party tax calculation API. One Tuesday afternoon, that API started lagging. It didn't crash—which would have been easier to handle—it just started taking 25 seconds to respond instead of 200 milliseconds. Because we were using a standard Akka actor to wrap these calls, our mailbox started filling up. Every request waited for that 25-second timeout, tying up a thread and consuming memory. Within twenty minutes, the "laggy" tax service had effectively DDoSed our own checkout service, bringing the entire site down. We weren't failing because the tax service was dead; we were failing because we kept trying to use it.

This is exactly why we use Circuit Breakers. The goal isn't to fix the downstream service—you can't control someone else's API—but to protect your own system from the fallout. A Circuit Breaker acts as a proxy that monitors for failures. When the failure rate hits a certain threshold, the breaker "trips" and enters an Open state. In this state, every subsequent call fails immediately without even attempting to hit the remote service. This gives the struggling downstream system room to breathe and prevents your own resources from being exhausted by endless waiting.

The Mechanics of the Trip

In Akka, the CircuitBreaker is provided as a pattern that wraps a Future-returning call. It operates like a state machine. When it's Closed, everything is normal; requests flow through. If the number of consecutive failures exceeds a limit you've set, it flips to Open. While Open, the breaker immediately returns a CircuitBreakerOpenException. After a cooldown period (the reset timeout), it enters the Half-Open state, allowing a single "test" request through. If that request succeeds, the circuit closes and we're back in business. If it fails, it flips right back to Open.

Here is how you actually set one up in your actor or service layer:

import akka.pattern.{CircuitBreaker}
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}

class TaxServiceProxy(implicit ec: ExecutionContext) {
  private val breaker = new CircuitBreaker(
    system,
    maxFailures = 5,
    callTimeout = 2.seconds,
    resetTimeout = 10.seconds
  )

  def getTaxRate(zipCode: String): Future[Double] = {
    breaker.withCircuitBreaker {
      // This is where the actual risky network call happens
      callLegacyTaxApi(zipCode)
    }
  }

  private def callLegacyTaxApi(zipCode: String): Future[Double] = {
    // Simulated API call
    Future { 
      // Logic that might time out or throw an exception
      1.05 
    }
  }
}

Managing the Reset Window

I've seen developers make the mistake of setting the resetTimeout too low. If you set it to 1 second, but the downstream service needs 30 seconds to reboot, you're just hammering it with "test" requests every second, potentially extending its outage. You have to align your breaker settings with the reality of the service you're calling. If it's a database that might be failing over to a replica, a 30-second window is more realistic.

You also need to decide how to handle the CircuitBreakerOpenException. You shouldn't just let it bubble up to the user as a 500 error. Instead, use this as a signal to provide a fallback. For my tax API disaster, the fallback was simple: use a cached average tax rate for that region. It wasn't 100% accurate, but the customer could still complete their purchase, and the site stayed online.

  • maxFailures: How many times the service can fail in a row before we give up.
  • callTimeout: The maximum time we're willing to wait for a single response before counting it as a failure.
  • resetTimeout: How long we wait in the Open state before trying again.



📋 Practical Task

Build a Resilient Weather Dashboard Proxy

You are building a weather dashboard that aggregates data from a notoriously unstable external Weather API. Your task is to implement a proxy service that prevents the dashboard from freezing when the Weather API becomes unresponsive.

Requirements:

  • Create a WeatherProxy class that uses an Akka CircuitBreaker.
  • Configure the breaker with a maxFailures of 3, a callTimeout of 1 second, and a resetTimeout of 5 seconds.
  • Implement a method getCurrentTemperature(city: String): Future[Double].
  • Inside getCurrentTemperature, wrap the API call in the circuit breaker.
  • Implement a fallback mechanism: if the circuit is Open or the call fails, the method should return a Future.successful(0.0) (a default "safe" value) instead of throwing an exception.
  • Simulate the "flaky" API by creating a helper method that randomly throws an exception or delays for 2 seconds to trigger the timeout.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.