Hey guys,
So I'm a complete newbie to this and a complete newbie to AKKA and to Scala, so I'm sure my question is simple, but after an hour of reading I cant really find a concise explanation.
Our application is currently simple enough: Our front-end will create a 'dispatcher' actor locally, which will connect to a number of 'worker' actors. It then receives configurations from the front-end and dispatches them as sizable computation work to each of the workers. At time of writing I really don't think we're going to need complex paths or sym-link-ish things or complex routing --we don't need an actor tree, just an actor list.
My understanding of the problem:
- Akka wants me to use it as a static factory to find actors. Once found, I acquire an `ActorRef`, which is a proxy for an actor object
somewhere {one of 'same JVM', 'same machine', 'same network'}
- The mechanism used to identify (and thus find) these actors is akin to a path on a file system --maybe a bit more like a URL with protocols and addresses and (presumably) credentials embedded in it.
My problem:
I need my actor environment to be configured in 3+ different ways:
- a unit-testing mode where everything is whiten the same JVM --for
consistency and least-suprise as an additional caveat I want messages to
be serialized using our serializer despite not them not actually needing it.
- a local-functional-testing mode where the actors exist on different JVMs on the same machine --ideally I'd also like to be able to flip this mode into most of mode 1 by specifying a `-DMakeActorsLocally=true`
option or similar
- a production mode where the actors exist on different jvms on different machines.
In the pursuit of #1 and #2 (haven't gotten around to #3 yet), I've cobbled these two lines together from the remote sample and the calculator sample:
//works for mode #2
val workerActor = context.actorSelection("akka.tcp://" + ProxyActor.SystemName + "@127.0.0.1:5150/user/" + ProxyActor.ActorName)
//for mode #1
val workerRouter = context.actorOf(
ProxyActor.props().withRouter(RoundRobinRouter(1)),
name = Proxy.ActorName
)
Now I could hack it together and do an if(mode1){ actor = ... } else if (mode2) { actor = ... }, but that's not nice. What I want to do is combine these two lines polymorphically so that this code doesn't change its behaviour between unit testing and deployment and everything in between. I'm not sure how to leverage paths and the various AKKA factories to do this.
What I believe is the solution:
Right now most of our unit testing leverages guice, such that any class takes the bulk of its dependencies through its constructor. At production these are all live classes, in development these are all mock/fake/stub classes. We do have
some classes that will act differently based on what boil down to system properties --we've written some tooling to add a couple features to the System.properties outside of simply getting and setting strings.
So, would like to do is have some static resource (perhalps a couple of enums?) that each specify a different strategy to produce actor refs,
ideally we would injcet these enums, but because of the static-factory-ness of AKKA I think my best bet (for simplicity --feel free to wow me with an amazing guice configuration but I cant really accept work I dont understand--) might be to push these values to AKKA configuration through the system properties (and/or static fields)
I've created
a gist containing the bulk of the functional code here --Its got too much of my projects markup on it for you to be able to compile it, but thanks to Scala (
im really liking this language) its all fairly short and concise. Hopefully you can read it. I haven't TDD'd pefectly, but I have been trying to drive my changes with a test fixture, so any change I make id like to be able to create a test for.
Any advice about coding style or testing strategy are welcome
- Specifically you'll note the pumping events behaviour I've got on the
JobDispatcherActor. I need the exact same behaviour on the ProxyActor.
With java I'd simply inject something and delegate to it, but with
scala... a trait? a mixin? Maybe KISS and just do what I'd do for java?
- Also, I discovered the `Nothing` type is a subclass of all classes, I presume `Any` has a similar relationship, but the bang-operator ('publish' method on actorref) takes an Any, which because of my confusion with pattern matching got me mixed up on what I was actually posting. Can I override this to take a less-open type? (such as a AKKAMessage?)
I've also got a more complex question about akka, guice,
and xstream over at stack-overflow, here.
Thanks for any help guys, if nothing else you've made my job pretty exciting for the past week or two!
-Geoff