Closed tfausak closed 9 years ago
Although Stoplight's readme lists some existing solutions, I would like to have a list here.
The readme fails to mention a couple others.
Martin Fowler's original blog post presents a Ruby implementation as well.
Pros:
Cons:
Example:
require 'circuit_b'
CircuitB.configure do |c|
c.state_storage = CircuitB::Storage::Memory.new
c.fuse 'example'
end
CircuitB('example') { p true }
# true
# => 0
Pros:
Cons:
Example:
require 'circuit_breaker'
class C
include CircuitBreaker
def example
p true
end
circuit_method :example
end
C.new.example
# true
# => true
Pros:
Cons:
Example:
require 'simple_circuit_breaker'
SimpleCircuitBreaker.new(3, 10).handle { p true }
# true
# => true
Pros:
#trip!
and #reset!
. Cons:
Example:
require 'circuit_breaker'
CircuitBreaker::Basic.new.execute { p true }
# true
# => nil
Pros:
Cons:
Example:
require 'breaker'
Breaker.circuit('example').run { p true }
# true
# => true
Pros:
Cons:
Example:
require 'circuitbox'
Circuitbox.circuit(:example).run { p true }
# D, [2015-02-03T09:05:04.307606 #1128] DEBUG -- : [CIRCUIT] closed: querying example
# true
# D, [2015-02-03T09:05:04.307920 #1128] DEBUG -- : [CIRCUIT] closed: example querie success
# => true
Gem | Stars | Commits | LoC |
---|---|---|---|
breaker | 12 | 36 | 409 |
circuit_b | 3 | 13 | 600 |
circuit_breaker | 204 | 23 | 563 |
circuitbox | 7 | 31 | 1066 |
simple_circuit_breaker | 10 | 13 | 173 |
stoplight | 5 | 299 | 1881 |
ya_circuit_breaker | 0 | 25 | 272 |
Now that I have done a (hopefully) objective overview, I'd like to dig in to some more subjective remarks.
breaker
This gem has the most in common with Stoplight. It's simple, has a great readme, and supports external data stores. Sort of. You can implement your own data store (or "repository" as they call it) and plug it in relatively easily. However there's no protocol to implement. In spite of being simple, it implements timeouts, which I think are orthogonal to circuit breakers.
In short, this gem is promising but has some rough edges. Had I found it when looking for existing circuit breaker gems, I probably would have forked it instead of starting from scratch.
circuit_b
This gem supports Redis data stores out of the box. It also has a comprehensive test suite and a good readme. So it's got a lot going for it. But it's main drawback is that it requires configuring circuits ahead of time. Since we were planning on wrapping many things with circuit breakers, that wasn't an option for us.
Sure, I could define a function that configures and runs the circuit all in one, but I would be fighting the library at that point. Plus it has two other problems: (1) it hasn't been updated in nearly five years, and (2) it doesn't return the result of the block. That means it's only useful for side effects.
circuit_breaker
Holy cow. This one actually implements a state machine. And it just gives me the impression that someone thought about it a lot. Which would be great, but it doesn't support external data stores. Since we run many front ends that need to be kept in sync, that's not acceptable.
I suspect that adding the ability to use external data stores would mess with the purity of actually using a state machine. It doesn't seem like a reasonable change to make to this gem.
circuitbox
If circuit_breaker was made by a computer scientist, circuitbox was made by a software engineer. It feels enterprise-y. That's not necessarily a problem, but in this case it's a little weird. Do circuits really need logging and metrics baked into the library?
This gem also uses ActiveSupport caches for storage. That kind of makes sense, based on its dependency on ActiveSupport, but it feels weird storing critical application data in a cache.
simple_circuit_breaker
This one definitely lives up to its name. It's a single file, less than 60 lines. I get the feeling this is where every other gem started out. This is what you'd do if you had to implement a circuit breaker during an interview.
That being said, it's not stupid, just simple. By not having any features (like external data stores), it can stay focused on the simplest thing that works. Unfortunately that doesn't cut it for me.
ya_circuit_breaker
I honestly don't know why this one exists. It acknowledges circuit_breaker and simple_circuit_breaker but doesn't say why you might want to use it instead.
Gem | Stars | Lines | Commits | Developer | Company |
---|---|---|---|---|---|
breaker | 12 | 409 | 36 | Adam Hawkins | - |
circuit_b | 3 | 600 | 13 | Aleksey Gureiev | - |
circuit_breaker | 204 | 563 | 23 | Will Sargent | Typesafe |
circuitbox | 7 | 1066 | 31 | Yann Armand | Yammer |
simple_circuit_breaker | 10 | 173 | 13 | Julius Volz & Tobias Schmidt | SoundCloud |
stoplight | 5 | 1881 | 299 | Cameron Desautels & Taylor Fausak | OrgSync |
ya_circuit_breaker | 0 | 272 | 25 | Patrick Huesler | Wooga |
I helped create Stoplight, which recently went into production. It could be useful to talk about the types of problems it solves and why the existing solutions weren't appropriate.