Circuit Breaker pattern – Go implement Part 3

In the previous post, i have implemented simple circuit-breaker pattern with Java, and today i will do it with Go

Talk about advanced of Go

+ Golang has great concurrency, the memory required for creating thread is very light.

+ Code is simple and very clean, easy to lean.

+ Appropriate and effective for service application.

+ ……

You can get more information at (https://hackernoon.com/why-i-love-golang-90085898b4f7)

Focus on main issue of this post, i will talk about step by step to implement breaker pattern

+ Create package and file breaker.go into the folder

+ Define state service and state breaker

type State inttype State int
type StateService int
const (
   STATE_CLOSE  State        = 1
   STATE_HALF_OPEN     State        = 2
   STATE_OPEN          State        = 3
   SERVICE_AVAILABLE   StateService = 1
   SERVICE_UNAVAILABLE StateService = 0
)

+ Define Breaker, BreakerEvent, OptionsConfig, CounterResult

type CounterResult struct {
   TotalRequests uint32
   TotalSucceses uint32
   TotalFailures uint32
   TotalRejects uint32
}

type Breaker struct {
   options OptionsConfig
   counter CounterResult
   events []chan BreakerEvent
   state State
   consecFailures uint32
}

type BreakerEvent struct {
   Code StateService
   Message string
}

type OptionsConfig struct {
   Attempts uint32
   TimeoutState time.Duration
   LimitFailure uint32
   MaxRequests uint32
   NameService string
}

+ Create new instance breaker

func NewBreaker(options *OptionsConfig) *Breaker {
if options == nil {
   options = &OptionsConfig{}
}
if options.Attempts == 0 {
   options.Attempts = 3
}
if options.TimeoutState == 0 {
   options.TimeoutState = 4 * time.Second
}
if options.LimitFailure == 0 {
   options.LimitFailure = 5
}
if options.MaxRequests == 0 {
   options.MaxRequests = 10000000
}
if options.NameService == "" {
   options.NameService = strconv.Itoa(int(time.Now().UnixNano()))
}
return &Breaker{options: *options, counter: CounterResult{}, state: STATE_CLOSE, consecFailures: 0}
}

+ Allow other services subscribe event

// other services subcriber
func (cb *Breaker) Subcriber() <-chan BreakerEvent {
   evenReader := make(chan BreakerEvent)
   outputChannel := make(chan BreakerEvent, 100)
   go func() {
   for event := range evenReader {
      select {
      case outputChannel <- event:
      default:<-outputChannel
      outputChannel <- event
      }
   }
   }()
   cb.events = append(cb.events, evenReader)
   return outputChannel
}

+ Create execute handle

// execute handle
func (cb *Breaker) Execute(handle func() ResponseCommand, timeout time.Duration) ResponseCommand {
   // add request
   atomic.AddUint32(&cb.counter.TotalRequests, 1)
   response := ResponseCommand{}
   // Reject all invoke when current state is OPEN
   if cb.IsOpen() {
   cb.Reject()
      response.Error = cb.ErrorServiceUnavailable()
      response.Data = nil
      return response
   }
   // run handle immediate and execute time is unlimited
   if timeout == 0 {
      response = handle()
   } else {
   // run handle with time execute is limited
   c := make(chan ResponseCommand, 1)
   go func() {
      c <- handle()
   }()
   select {
      case r := <-c:
      response = r
      close(c)
      case <-time.NewTimer(timeout).C:
      response.Error = cb.ErrorTimeoutExecute()
      response.Data = nil
   }
   }
   // check for any errors
   if response.Error != nil {
      cb.Failure()
   } else {
      cb.Success()
   }
   return response
}

You can reference full source and demo at : circuit-breaker-go

Leave a comment