rubyist / circuitbreaker

Circuit Breakers in Go
MIT License
1.12k stars 109 forks source link

Value alignment issue on 32-bit systems (ARM) #43

Open abferm opened 7 years ago

abferm commented 7 years ago

This library suffers from go issue #599 when compiled for ARM using the gc compiler. The gccgo compiler appears to take care of it, but that limits the go version to <=1.6.1 for official gccgo releases. The following padding & reordering of the Breaker struct fixes the issue.

`// Breaker is the base of a circuit breaker. It maintains failure and success counters // as well as the event subscribers. type Breaker struct { // BackOff is the backoff policy that is used when determining if the breaker should // attempt to retry. A breaker created with NewBreaker will use an exponential backoff // policy by default. BackOff backoff.BackOff

// ShouldTrip is a TripFunc that determines whether a Fail() call should trip the breaker.
// A breaker created with NewBreaker will not have a ShouldTrip by default, and thus will
// never automatically trip.
ShouldTrip TripFunc

// Clock is used for controlling time in tests.
Clock clock.Clock

_              [4]byte // pad to fix golang issue #599
consecFailures int64
lastFailure    int64 // stored as nanoseconds since the Unix epoch
halfOpens      int64
counts         *window
nextBackOff    time.Duration
tripped        int32
broken         int32
eventReceivers []chan BreakerEvent
listeners      []chan ListenerEvent
backoffLock    sync.Mutex

}`

abferm commented 7 years ago

The issue also presents itself in 386 binaries. The issue can be demonstrated by compiling the following code for a 64-bit system and a 32-bit system and running both. Switching the import to my fork will make the code work for both 32-bit and 64-bit systems.

package main

import (
    "log"

    circuit "github.com/rubyist/circuitbreaker"
)

func main() {
    cb := circuit.NewThresholdBreaker(10)
    events := cb.Subscribe()
    go func() {
        for {
            e := <-events
            // Monitor breaker events like BreakerTripped, BreakerReset, BreakerFail, BreakerReady
            log.Println(e)
        }
    }()

    cb.Success()
    cb.Fail()
    cb.Reset()
}