breaker

package
v0.0.0-...-8dafbfe Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2015 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

The breaker package provides circuit breaker primitives to enable one to safely interact with potentially-unreliable subsystems in a way that allows a graceful alternative behavior while in degraded state.

For instance, if your server depends on an external database and it becomes unavailable, your server can use a breaker to track these failures and provide an alternative workflow during this period of unavailability.

A circuit has two states:

CLOSED: The system decorated with this breaker is assumed to be available and the dependents thereof may use it freely.

OPEN: The system decorated with this breaker is assumed to be unavailable and the dependents thereof should not use it at this time.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Consecutive

type Consecutive struct {
	// RetryTimeout is added to the time when the circuit first opens to determine
	// the next time the decorating operation will be allowed to occur.
	RetryTimeout time.Duration
	// FailureAllowance is the maximum consecutive failures that may occur before
	// the circuit will open.
	FailureAllowance uint
	// contains filtered or unexported fields
}

Consecutive provides a simple circuit breaker with a deadline expiration strategy to determine when to reclose itself. Its initial state is CLOSED and will only open once a threshold of consecutive failures is reached.

It is concurrency safe.

Example
package main

import (
	breaker "."
	"fmt"
	"time"
)

// RemoteService is a fictitious interface to an encapsulation of some
// unreliable subsystem that is outside of our domain of control.  It should
// be treated for this example as merely a recording of behavior.
type RemoteService struct {
	// The subsystem's circuit breaker.
	Breaker breaker.Consecutive
	// The pre-recorded success or failure results that are used to drive
	// the behavior of this example.
	Results []bool
}

// ConductRequest is the supposed interface point for user's of this subsystem.
// They call it as necessary to perform whatever work to yield the result they
// want.
func (s *RemoteService) ConductRequest() {
	// For purposes of not convoluting the example, we use real sleep operations
	// here.
	time.Sleep(time.Second/2 + time.Second/4)

	// If the circuit is broken, merely bail.
	if s.Breaker.Open() {
		fmt.Println("Unavailable; Trying Again Later...")

		return
	}

	// Emulate the actual remote interface here that is supposedly unreliable.
	err := s.performRequest()
	// WARNING: We make an implicit assumption that any err value is retryable
	// and not a permanent error.
	if err != nil {
		fmt.Println("Operation Failed")
		s.Breaker.Fail()
	} else {
		fmt.Println("Operation Succeeded")
		s.Breaker.Succeed()
	}
}

// performRequest models an interaction with an unreliable external
// system---e.g., a remote API server.
func (s *RemoteService) performRequest() error {
	result := s.Results[0]
	s.Results = s.Results[1:]

	if !result {
		return fmt.Errorf("Temporary Unavailable")
	}

	return nil
}

func main() {
	subsystem := &RemoteService{
		Breaker: breaker.Consecutive{
			FailureAllowance: 2,
			RetryTimeout:     time.Second,
		},
		Results: []bool{
			true,  // Success.
			true,  // Success.
			false, // One-off failure; do not trip circuit.
			true,  // This success negates past failures.
			false, // String of contiguous failures to create open circuit.
			false, // Open.  :-(
			false, // Open; however, we've timed out.
			true,  // We have a success here.
		},
	}

	subsystem.ConductRequest()
	subsystem.ConductRequest()
	subsystem.ConductRequest()
	subsystem.ConductRequest()
	subsystem.ConductRequest()
	subsystem.ConductRequest()
	subsystem.ConductRequest()
	subsystem.ConductRequest()
	subsystem.ConductRequest()
}
Output:

Operation Succeeded
Operation Succeeded
Operation Failed
Operation Succeeded
Operation Failed
Operation Failed
Unavailable; Trying Again Later...
Operation Failed
Operation Succeeded

func (*Consecutive) Fail

func (b *Consecutive) Fail()

Fail marks the decorated subsystem as having an operation fail and may trigger its subsequent circuit opening.

This should only be called if you can divine that the underlying failure is or should be considered transient for the given domain of work. For instance, high latency, erroneous responses, unavailability count as so-called temporary failures. Things like invalid user queries count as permanent errors and would never make sense to be retried.

func (*Consecutive) Open

func (b *Consecutive) Open() bool

Open indicates whether the circuit for this subsystem is presently open.

func (*Consecutive) Reset

func (b *Consecutive) Reset()

Reset returns this circuit back to its default state: closed.

This should be called if you can divine that the underlying subsystem has become unavailable before the deadline threshold has been reached.

func (*Consecutive) String

func (b *Consecutive) String() string

func (*Consecutive) Succeed

func (b *Consecutive) Succeed()

Succeed marks the decorated subsystem as having an operation succeed and will its circuits closure if it's presently open.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL