Is there a good way to distinguish usual methods calls and typed actor calls?

36 views
Skip to first unread message

Oleg Galako

unread,
May 20, 2011, 2:00:55 PM5/20/11
to akka...@googlegroups.com
Hi,

I found myself fighting with usual/actor calls mess and i started thinking of a good way to separate them... One possible solution is to name all remote methods special way e.g. starting with 'remote' but it's hard to enforce (only runtime reflection checks at app start or something like that).

Untyped actors are good in this sense - but they are not type safe.

Any ideas?

√iktor Ҡlang

unread,
May 20, 2011, 2:23:41 PM5/20/11
to akka...@googlegroups.com
Hi Oleg!

On Fri, May 20, 2011 at 8:00 PM, Oleg Galako <ojo...@gmail.com> wrote:
Hi,

I found myself fighting with usual/actor calls mess and i started thinking of a good way to separate them... One possible solution is to name all remote methods special way e.g. starting with 'remote' but it's hard to enforce (only runtime reflection checks at app start or something like that).


Can you give an example of the problem?
 
Untyped actors are good in this sense - but they are not type safe.

They are extremely type safe, you'll only process the messages you're looking for, and those are typed.
 
Cheers,



Any ideas?

--
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To post to this group, send email to akka...@googlegroups.com.
To unsubscribe from this group, send email to akka-user+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.



--
Viktor Klang

Akka Tech Lead
Typesafe - Enterprise-Grade Scala from the Experts

Twitter: @viktorklang

Oleg Galako

unread,
May 21, 2011, 1:36:02 AM5/21/11
to akka...@googlegroups.com
Thanks for the answer, Viktor!

The problem is how should i structure my code so that it can be clearly understandable which parts are used to locally wire different domain logic parts and which parts are used to make the system easily scalable and distributed. By remote or actor calls i mean those done by typed actor proxies and by direct/usual calls i mean just plain JVM method calls. Here is what i tried to implement. 

First of all i wanted to create actor based properties with listeners (instead of reading rarely changing properties via remote calls every time i need their value). 

Then let's say i have a map and movable objects on that map. I want the map and objects to be distributable so i made them as actors. When object moves (its 'position' property changes) it sends notifications to all listeners. One of those listeners belongs to the map actor. The map actor's purpose is to provide info on objects around some coordinates. I also wanted to make the code loosely coupled and made each property (e.g. object's location) a separate actor. And my first attempt ended with code full of remote calls (e.g. asking for property owner is an actor call, asking for object position is an actor call, even asking for object id is an actor call).

So i tried to separate the logic i need to be distributed and domain wiring logic. Generally speaking i need to have some custom code at the remote (e.g. map actor's) node to package all needed info and send it so i don't query every part of it via actor calls. This is what i call domain wiring, the logic doesn't belong to the actor itself, it belongs to those who call the actor, but it should be executed at actors node to reduce the number of remote calls.

And by 'type safe' i mean that compiler can tell me if i can process a message and if i expect the right result, which is not the case with untyped actors.

One more try to rephrase the problem: 
* you have an actor with complex state (lets call it server)
* you want to provide a flexible interface to the state, so some server side processing could be made before sending the result to the clients
* you don't want to put the processing logic (which actually belongs to the client) in the server code
How do you separate the remote interface and the local processing interface?

Thanks again for your attention.

Oleg Galako

unread,
May 21, 2011, 11:33:46 AM5/21/11
to akka...@googlegroups.com
After some thinking and experiments i've noticed that the problem has some similar moments with ORM's. E.g. lazy vs eager loading (in my case remote calls vs serialization) and server side queries (this is what i called domaing wiring on server side). I still haven't found solutions to the server side queries but the parts looks quite possible. I tried to enumarate requirements and implemented them in a draft, i think i'll take the latest TypedActor code from master to complete my implementation (looks like i need the separate traits feature).

Maybe i'm just bad at explaining but i think i'm talking about a _fundamental feature that should be included in the library_ : "Remote properties with listeners". Here are the requirements i've written:

1. To be able to add listeners to a property it must be a separate class (adding addListenerToSomething methods for every property isn't good)
2. Properties should be serializable to be able to travel between nodes
3. Properties should be able to give their value without actor calls, so they cannot be actors
4. A record containing properties should be the actor to allow atomic operations on sets of properties
5. Public writing to a property should be done via remote call
6. Inner (by the owner record) reads and writes and public reads should be direct calls. For lazy properties public read should be a remote call
7. To allow public actor calls via property it must contain the owner ActorRef

Here is my first draft of implementation:
class RecordActor extends TypedActor {
  class Property[T](@volatile private[test] var value: T) {
    private val owner: RecordActor = RecordActor.this // TODO: this should be ActorRef
    private val myIndex = lastPropertyIndex
    properties.update(myIndex, this.asInstanceOf[Property[Any]])
    lastPropertyIndex += 1

    def apply() = value // LazyProperty will allow remote reads
    def update(newVal: T): Future[T] = future { // ReadOnlyProperty will not allow writes
      owner.updateProp(myIndex, newVal)
      value = newVal
      newVal
    }
  }

  private var lastPropertyIndex = _
  private lazy val properties = new collection.mutable.HashMap[Int, Property[Any]] // this can be just random access List

  // this should be remote
  private def updateProp(index: Int, value: Any) {
    properties(index).value = value
  }
}

class Player(_id: String) extends RecordActor {
  val id = new Property(_id)
  val name = new Property("Joe")
  val position = new Property(Point(0, 0))
}

√iktor Ҡlang

unread,
May 21, 2011, 12:17:34 PM5/21/11
to akka...@googlegroups.com

Is it just me or doesn't sound like a reinvention of EJBs with local interfaces, remote interfaces etc?

Oleg Galako

unread,
May 21, 2011, 1:21:35 PM5/21/11
to akka...@googlegroups.com
Heh, maybe, i'm not familiar with this part of EJB spec, probably have to read about it to understand it better.
A year ago i reinvented Typed Actors (https://groups.google.com/d/msg/akka-user/WWECfJxRwGM/BN7Ttj1nyyAJ), this time it's something else.

Is there something wrong with the local/remote EJB interfaces? I just wanted type safe and optimized remote properties with listeners, sounds pretty natural, isn't it? Maybe you can give me a hint if what i need can be done in a different and better way?

√iktor Ҡlang

unread,
May 21, 2011, 1:30:52 PM5/21/11
to akka...@googlegroups.com

It sounds like you need a Datagrid. Normally you want to send logic to data and not data to logic, and you want to have a different datamodel for queries and one for commands.

A common problem is that people query objects instead of commanding them, the old "Tell, don't ask." OO principle.

Cheers,
V

Oleg Galako

unread,
May 22, 2011, 11:25:24 AM5/22/11
to akka...@googlegroups.com
The 'Remote queries' feature seems to be easy with the cake pattern. I can just create traits with additinal operations (queries) and mix them to the main class at instantiation ('server' actor creation).

And my properties implementation seems almost done, now i just need to use your new TypedActor code to be able to create proxies for multiple interfaces.

Usage looks like this (i'm including the code because i hope you can grasp my idea and either tell me if i'm missing something important or agree it's a cool and useful feature):

class Player extends RemoteRecord {
  val id = property("333")
  val name = property("Joe")
  val position = property(Point(0, 0))

  override val remote = new RecordActor { // the remote interface, also includes hidden service methods used by properties
    def moveTo(p: Point) {
      position.set(p) // direct setting of value
    }
  }
}


  def main(args: Array[String]) {
    val p = new Player // let's pretend we got 'p' by a remote operation (and deserialization)

    // just look at the following code, isn't it easy and readable while doing some cool things?
    p.position.addListener(new ChangeListenerActor[Point] { // actually this should be a TypedActor creation, then the new actorRef is passed to p's home node as a 'callback'
      def onNewValue(value: Point) { println("----> " + value) } // we are not sending the handler itself anywhere, so no problems with closure serialization etc
    })
    println(p.position()) // no remote calls, the value is available locally after deserialization
    p.position() = Point(1, 1) // position's update() method uses hidden methods from RecordActor to make this call send update to p's home node
    p.remote.moveTo(Point(2, 2)) // and here is what i wanted in my first message in this thread - we clearly see that this call is remote
  }

----------------

Now if some operation (like getObjectAround of the map of movable objects i mentioned above) returns me 100 players and i want to get their names i will not do 100 remote calls. Because Player objects are serializable beans with an ActorRef (the 'remote' field) to execute remote operations when needed.

I think my case is quite common and looks like the solution is quite easy. Don't you think the rich typed actor with properties can be a good tool in the akka toolset?

I'm asking because i'm not sure i'm good enough to support such a library myself. So i can either implement it for myself and use it in my project or we can work together to imrove it and add it to akka.

Thanks,
Oleg.

√iktor Ҡlang

unread,
May 22, 2011, 2:14:42 PM5/22/11
to akka...@googlegroups.com
On Sun, May 22, 2011 at 5:25 PM, Oleg Galako <ojo...@gmail.com> wrote:
The 'Remote queries' feature seems to be easy with the cake pattern. I can just create traits with additinal operations (queries) and mix them to the main class at instantiation ('server' actor creation).

And my properties implementation seems almost done, now i just need to use your new TypedActor code to be able to create proxies for multiple interfaces.

Usage looks like this (i'm including the code because i hope you can grasp my idea and either tell me if i'm missing something important or agree it's a cool and useful feature):

class Player extends RemoteRecord {
  val id = property("333")
  val name = property("Joe")
  val position = property(Point(0, 0))

  override val remote = new RecordActor { // the remote interface, also includes hidden service methods used by properties
    def moveTo(p: Point) {
      position.set(p) // direct setting of value
    }
  }
}


  def main(args: Array[String]) {
    val p = new Player // let's pretend we got 'p' by a remote operation (and deserialization)

So p is a remote proxy TypedActor?
 

    // just look at the following code, isn't it easy and readable while doing some cool things?
    p.position.addListener(new ChangeListenerActor[Point] { // actually this should be a TypedActor creation, then the new actorRef is passed to p's home node as a 'callback'


but p.position would be a remote call no?
 
      def onNewValue(value: Point) { println("----> " + value) } // we are not sending the handler itself anywhere, so no problems with closure serialization etc
    })
    println(p.position()) // no remote calls, the value is available locally after deserialization

Then p is not a remote proxy?
 
    p.position() = Point(1, 1) // position's update() method uses hidden methods from RecordActor to make this call send update to p's home node
    p.remote.moveTo(Point(2, 2)) // and here is what i wanted in my first message in this thread - we clearly see that this call is remote
  }

----------------

Now if some operation (like getObjectAround of the map of movable objects i mentioned above) returns me 100 players and i want to get their names i will not do 100 remote calls. Because Player objects are serializable beans with an ActorRef (the 'remote' field) to execute remote operations when needed.

I think my case is quite common and looks like the solution is quite easy. Don't you think the rich typed actor with properties can be a good tool in the akka toolset?

I think it needs some time as a stand alone project, to prove it's use for people, and if it's gaining adoption, we will consider moving it into Akka itself.
 

I'm asking because i'm not sure i'm good enough to support such a library myself. So i can either implement it for myself and use it in my project or we can work together to imrove it and add it to akka.

Just be sure to write a ton of unit tests so you can verify what gets called remotely and what doesn't. :-)

Cheers,

 

Thanks,
Oleg.

--
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To post to this group, send email to akka...@googlegroups.com.
To unsubscribe from this group, send email to akka-user+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.

Oleg Galako

unread,
May 22, 2011, 9:15:38 PM5/22/11
to akka...@googlegroups.com

  def main(args: Array[String]) {
    val p = new Player // let's pretend we got 'p' by a remote operation (and deserialization)

So p is a remote proxy TypedActor?
No, p itself is a bean, it contains a remote proxy TypedActor in its 'remote' field. But we can get p as a result of some other remote call. I guess a little custom deserialization might be needed, i'll try to implement it. 

 
    // just look at the following code, isn't it easy and readable while doing some cool things?
    p.position.addListener(new ChangeListenerActor[Point] { // actually this should be a TypedActor creation, then the new actorRef is passed to p's home node as a 'callback'
but p.position would be a remote call no?
No, p.position is local.
 
I think it needs some time as a stand alone project, to prove it's use for people, and if it's gaining adoption, we will consider moving it into Akka itself. 

I'm asking because i'm not sure i'm good enough to support such a library myself. So i can either implement it for myself and use it in my project or we can work together to imrove it and add it to akka.

Just be sure to write a ton of unit tests so you can verify what gets called remotely and what doesn't. :-)
 Ok, lets see what i can do. I think i can even implement it in 1.1 with 'receive' overriding...

I'll let you know of my results, thanks for your time.

Oleg Galako

unread,
May 23, 2011, 9:38:30 AM5/23/11
to akka...@googlegroups.com
Looks like i have to wait for future versions. Was hoping to get a working remote sample today (local-actor based one worked ok), only had serialization left to do. But i wasted too much time trying to implement it with the 'SOLID' 1.1 serialization interfaces (e.g. i was really surprised when i had to provide deserializer from the same class as its result).

So for now i'll have to go with something more basic like untyped actors.

√iktor Ҡlang

unread,
May 23, 2011, 10:02:39 AM5/23/11
to akka...@googlegroups.com
On Mon, May 23, 2011 at 3:38 PM, Oleg Galako <ojo...@gmail.com> wrote:
Looks like i have to wait for future versions. Was hoping to get a working remote sample today (local-actor based one worked ok), only had serialization left to do. But i wasted too much time trying to implement it with the 'SOLID' 1.1 serialization interfaces (e.g. i was really surprised when i had to provide deserializer from the same class as its result).


Why not just rely on Java Serialization for now?
 
So for now i'll have to go with something more basic like untyped actors.

--
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To post to this group, send email to akka...@googlegroups.com.
To unsubscribe from this group, send email to akka-user+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.

Oleg Galako

unread,
May 23, 2011, 12:41:58 PM5/23/11
to akka...@googlegroups.com
Why not just rely on Java Serialization for now?
Well i think i've read http://akka.io/docs/akka/1.1/scala/serialization.html too much: 
"If you are sending messages to a remote Actor and these messages implement one of the predefined interfaces/traits in the akka.serialization.Serializable.* object, then Akka will transparently detect which serialization format it should use as wire protocol and will automatically serialize and deserialize the message according to this protocol. "

And i just forgot about the possibility of using Java Serialization. But i tried it and it worked! Thank you!
I've got this code working with server/client in 2 SBT windows:

object Server {
  def main(args: Array[String]) {
    remote.start("localhost", 2552)
    val provider = TypedActor.newInstance(classOf[SomeKindOfPlayerProvider], classOf[SomeKindOfPlayerProviderImpl])
    remote.registerTypedActor("provider", provider)
  }
}

object Client {
  class Listener[T] extends TypedActor with ChangeListenerActor[T] {
    def onNewValue(value: T) { println("---> " + value) }
  }

  def main(args: Array[String]) {
    val remoteProvider = remote.typedActorFor(classOf[SomeKindOfPlayerProvider], "provider", 5000L, "localhost", 2552)
    val player = remoteProvider.getPlayer
    println("Position: " + player.position())
    val listener = TypedActor.newInstance(classOf[ChangeListenerActor[Point]], classOf[Listener[Point]])
    remote.start("localhost", 2553)
    remote.registerTypedActor("listener", listener)
    player.position.addListener(listener)
    player.position() = Point(1, 2)
    player.remote.moveTo(Point(2, 2))
  }
}

The only problem is i had to switch to using classOf[] instead of constructor for the listener because RemoteTypedActorSerialization.fromBinaryToRemoteTypedActorRef instantiates the class. I thought it could find my registered instance... Is there a kind of actorRef that is bound to an instance?

Now i just need to clean the code of some hacks and stuff and i can use it. Cool!

Thank you for your attention and help, Viktor.

Oleg Galako

unread,
May 24, 2011, 12:48:46 PM5/24/11
to akka...@googlegroups.com
Hi, Viktor!

After playing with my implemention i noticed that i dont gain much more than a case class with actorRef. Some dark magic with initialization, extra pointers and stuff like that remind of me leaking abstractions. I'll see if can simplify and constraint it deep enough. If not i'll just try case classes with actorRef packed inside for remote operations.

The question left unanswered is how can i get a portable ActorRef bound to an instance? Or isn't it implemented yet? If so what is the best way (if there is one) to implement it in 1.1?
Reply all
Reply to author
Forward
0 new messages