Circuit breaker

The circuit breaker [pattern] is a way to handle transient failures in distributed software.

When requests to services fail, a circuit breaker will automatically open, preventing any further requests from being sent to the failing service. The circuit breaker will remain open for a configurable amount of time, after which it will automatically close, allowing further requests to be sent again to the service.

Circuit breakers complement retry mechanism. Whereas a retry mechanism will keep retrying a failing service until it succeeds, a circuit breaker will trip when the error rate exceeds a configured threshold and it will prevent any further requests from being sent to the failing service for a configured period of time.

Both are solutions for improving fault tolerance, and the two solutions work particularly well in combination. If a service is failing, it is likely that it will continue to fail for a period of time, until its failure mode is resolved through disaster recovery mechanisms. While disaster recovery is ongoing, a circuit breaker will help to prevent the recovering system from being overwhelmed by retries.

Example implementation (pseudo-code)

public class CircuitBreaker
{
  private int failureCount = 0;

  /**
   * Number of failures before tripping.
   */
  private int failureThreshold = 5;

  /**
   * Time to wait before allowing requests again.
   */
  private TimeSpan timeout = TimeSpan.FromSeconds(30);

  private DateTime lastFailureTime;

  public bool execute(Func<bool> action)
  {
    if (isOpen())
    {
      /* Short-circuit the request. */
      return false;
    }

    try
    {
      bool result = action();
      reset();

      return result;
    }
    catch (Exception)
    {
      failureCount++;
      lastFailureTime = DateTime.Now;

      return false;
    }
  }

  private bool isOpen()
  {
    if (failureCount >= failureThreshold)
    {
      if (DateTime.Now - lastFailureTime > timeout)
      {
        /* Move to half-open state. */
        failureCount = 0;

        return false;
      }

      return true;
    }

    return false;
  }

  private void reset() => failureCount = 0;
}
public class OrderService
{
  private CircuitBreaker circuitBreaker = new CircuitBreaker();

  public void placeOrder(Order order)
  {
    // Logic to handle order placement...

    bool paymentSuccessful = circuitBreaker.execute(() =>
        paymentService.processPayment(order.paymentDetails));

    if (!paymentSuccessful)
    {
      // Handle payment failure, eg., notify user, log error, etc.
    }
    else
    {
      // Continue handling the order...
    }
  }
}