I am trying to wrap my head around Akka/actors for the first time, and am a bit confused over the granularity of each Actor's responsibilities.
In my app there are Widget
s that can be registered/unregistered with a WidgetRegistrar
. To register itself with the Registrar
and Widget
is passed to the registerWidget
method:
interface WidgetRegistrar {
public void register(Widget w);
}
When a Widget
attempts to register, a verification process occurs. If this process passes, then the Widget
presents a URL that must be constantly (once a second) polled and checked (with an HTTP GET) to make sure that URL is still healthy.
My question here is: how should this work load be spread amongst actors?
I can think of several different strategies right off the bat:
WidgetRegistrar
actor that first somehow delegates to the WidgetVerifier
actor (see below), and if verified, updates the WidgetChecker
actor with the newly-registered/verified Widget
WidgetVerifier
actor that verifies a Widget
attempting to register itselfWidgetChecker
that checks a URL for each registered/verified Widget
Or a different strategy:
WidgetRegistrar
actor that first somehow delegates to the WidgetVerifier
actor (see below), and if verified, somehow instantiates a new WidgetChecker
actor (see below)WidgetVerifier
actor that verifies a Widget
attempting to register itselfWidgetChecker
for each registered/verified Widget
Or a different strategy:
WidgetRegistrar
actor that verifies Widget
s right there on the spot (instead of delegating out to a separate actor), and if verified, updates the WidgetChecker
actor with the newly-registered/verified Widget
WidgetChecker
that checks a URL for each registered/verified Widget
...the list of variations goes on and on.
So I ask: what is the granularity of an Akka actor, and how do I know when I should break functionality out into another actor and somehow connect the two actors?
Akka ideology is 'let it crash', so it's best to isolate potentially dangerous functionality into a separate actor.
How i would do that - sample actor hierarchy:
/master
/validator
/authentication
/capability
/registrar
/widget1
/widget2
/widget3
Assuming that you may want to have more functionality in your registrar other than register/unregister for a single widget, it's would be good to separate widgets under specific root - so, for instance, if your widget has functionality like 'update', you invoke this logic in /registrar/widget1
, and if update has failed, widget1
actor will die. Depending on your needs you may want to require either to reregister the widget, or set the supervisor hierarchy to restart the widget actor automatically.
With validators/verifiers and other logic - you can build either pipeline (sequential processing) or scatter-gather (parallel) on your validators, for instance:
AttemptRegister(WidgetInfo)
ask
pattern), and is expecting Accept(WidgetInfo)
or Reject(WidgetInfo)
- if there are no rejections - it will send RegisterWidget
to /registrar
and registrar will spawn a new /registrar/widget2
.Of course, it all depends on the concrete use case - for instance:
/validator/capability/doOrDieActor1
../authentication
will send Pass
or Fail
to ../authorization
that will send it to capability
etc - and only the final actor will send ValidationSucceeded
to /validator
, which will in turn send RegisterWidget
event to registrar