-
Notifications
You must be signed in to change notification settings - Fork 1
ProtectAid
In normal operation the mailbox will not quickly be full. In fact,
there is no other limit than the total memory of the system or
Int.MaxValue, which ever comes first for a mailbox in any actor.
(Formally this depends on the setting in SystemParameters
,
which can be influenced by the user to be a lower value. The
ActorContext.system
works with default settings at which this
holds true.)
But, it should not come this far. If the system
is designed well, mailboxes should be empty or contain very few
messages most of the time. This is because handling the messages should
be swift enough to make it so. If the system is not able to handle the
load, it should be throttled at the start of the message pipeline.
This could be, for example, the location where user requests come in,
typically a web server or so. Or, if the system is crunching data
from a database at reading that data.
In any case, there may be reasons why you want to limit the number of messages that are send to an actor. This limit can also be used to create back pressure and implement a reactive stream.
WARNING: Still version 0.4.3, NOT compatible with 0.5.0, working on it ;)
In order to protect you actor use the mixin ProtectAid
. This
adds a field and a method that must be implemented.
/**
* The number of letters in the mailbox that issues an alarm. This must be a constant, since
* it is called in a synchronized environment, and is called on every letter posted. */
protected val protectLevel: Int
/**
* Implement an event handler for the situation the mailbox exceeds the limit set in protectLevel,
* (full = true) and for when mailbox, stash and event queues are all depleted (full = false).
* Each call happens only once, and you always receive an call signalling empty queues after a
* a call with full=true was made and before the next call with full=true is made. When stop(Finish)
* is called the call sizeAlarm(false) will come after the last letter is processed and but before
* stopped() is called. When stop(Direct) is called, the sizeAlarm(true/false) may not come at all.
* The size parameter reflects the total number of size alarms during the lifetime of the actor
* up to now, this one included. */
protected def protectAlarm(full: Boolean): Unit
With protectLevel
you set a high level watermark that, if reached triggers the protectAlarm(true)
callback. The message is not refused and still added to the mailbox. This also applies
to each subsequent message, but the protectAlarm
in not called again. The idea is that you
implement a handler that prohibits the further sending of new messages to this actor,
(where a few extra that cannot be stopped are not a problem) until protectAlarm(false)
is called. The latter happens only when the actor has completely handled all messages left,
including those that were posted after the alarm was raised.
The call to protectAlarm
comes, like all other callbacks, in its own thread inside the
actor and never when a letter is handled. It is completely save to access the actors
internal state from within the callback. Typically you send an other actor a message
to slow down a little. Only after the protectAlarm
has been completed the next letter will
be processed.
Since there may be some time between reaching the high level watermark
and the subsequent execution of the protectAlarm
callback, it may happen that the
number of letters has changed in the mean time. This does not erase the callback
unless in the unlikely event the message box has become completely empty.
So if you check the mailbox size inside the protectAlarm
handler you may find any value.