* Add Circuit Breaker to akka.pattern for general use. Circuit breaker implementation as described by Michael T. Nygard in Release It!. Fixes #1734
* Uses finite state machine for three states: Closed, Open, Half-Open
* Closed state allows calls through, and on sequential failures exceeding the max# set - transitions to Open state. Intervening successes cause the failure count to reset to 0
* Open state throws a CircuitOpenException on every call until the reset timeout is reached which causes a transition to Half-Open state
* Half-Open state will allow the next single call through, if it succeeds - transition to Closed state, if it fails - transition back to Open state, starting the reset timer again
* Allow configuration for the call and reset timeouts, as well as the maximum number of sequential failures before opening
* Supports async or synchronous call protection
* Callbacks are supported for state entry into Closed, Open, Half-Open. These are run in the supplied execution context
* Both thrown exceptions and calls exceeding max call time are considered failures
* Uses akka scheduler for timer events
* Integrated into File-Based durable mailbox
* Sample documented for other durable mailboxes
This commit is contained in:
parent
85c263e077
commit
6a415f0e9b
15 changed files with 1266 additions and 25 deletions
|
|
@ -50,6 +50,8 @@ import akka.dispatch.MailboxType
|
|||
import akka.dispatch.MessageQueue
|
||||
import akka.actor.mailbox.DurableMessageQueue
|
||||
import akka.actor.mailbox.DurableMessageSerialization
|
||||
import akka.pattern.CircuitBreaker
|
||||
import akka.util.duration._
|
||||
|
||||
class MyMailboxType(systemSettings: ActorSystem.Settings, config: Config)
|
||||
extends MailboxType {
|
||||
|
|
@ -65,20 +67,23 @@ class MyMessageQueue(_owner: ActorContext)
|
|||
extends DurableMessageQueue(_owner) with DurableMessageSerialization {
|
||||
|
||||
val storage = new QueueStorage
|
||||
// A real-world implmentation would use configuration to set the last
|
||||
// three parameters below
|
||||
val breaker = CircuitBreaker(_owner.system.scheduler,5,30.seconds,1.minute)
|
||||
|
||||
def enqueue(receiver: ActorRef, envelope: Envelope) {
|
||||
def enqueue(receiver: ActorRef, envelope: Envelope): Unit = breaker.withSyncCircuitBreaker {
|
||||
val data: Array[Byte] = serialize(envelope)
|
||||
storage.push(data)
|
||||
}
|
||||
|
||||
def dequeue(): Envelope = {
|
||||
def dequeue(): Envelope = breaker.withSyncCircuitBreaker {
|
||||
val data: Option[Array[Byte]] = storage.pull()
|
||||
data.map(deserialize).orNull
|
||||
}
|
||||
|
||||
def hasMessages: Boolean = !storage.isEmpty
|
||||
def hasMessages: Boolean = breaker.withSyncCircuitBreaker { !storage.isEmpty }
|
||||
|
||||
def numberOfMessages: Int = storage.size
|
||||
def numberOfMessages: Int = breaker.withSyncCircuitBreaker { storage.size }
|
||||
|
||||
/**
|
||||
* Called when the mailbox is disposed.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue