Java Akka typed immutable behavior : can we safely mix with mutable arguments?

akka-typed
java

#1

Hi there,
I’m akka beginer, in the typed actor documentation we can find following sample :

public static Behavior<RoomCommand> behavior() {
  return chatRoom(new ArrayList<ActorRef<SessionCommand>>());
}

**private** static Behavior<RoomCommand> chatRoom(List<ActorRef<SessionCommand>> sessions) {
  return Behaviors.immutable(RoomCommand.class)
    .onMessage(GetSession.class, (ctx, getSession) -> {
     ...
      List<ActorRef<SessionCommand>> newSessions = **new ArrayList<>(sessions);**
**      newSessions.add(ses);**
      return chatRoom(**newSessions**);
    })
    .onMessage(PublishSessionMessage.class, (ctx, pub) -> {
    ...
      **sessions.forEach(...);**
      return Behaviors.same();
    })
    .build();
}

I like this api but I can’t find any reason for allocating a new ArrayList on each “call” to GetSession, in this specific case at least. I just wanted confirmation it would be safe to just update and keep the ‘sessions’ list instance in this sample ?

I’m interested by the actor model to avoid both synchronization primitives or new allocations (threadlocal things), for some mutable states.

Thanks!


#2

If you look at the typed Java mutable vs immutable sample there :

https://akka.io/blog/2017/05/08/typed-mutable-vs-immutable

One can see that mutable version is far different and longer than immutable one.

I think we can write mutable behaviors almost the same way we write immutable ones, by just giving a mutable bean container argument to the static private function creating a behavior. Access will end up being serialized so it’s safe usage.
In this sample that would mean adding 2 fields, mutable ‘index’ and final ‘workers’ to class ImmutableRoundRobin, then giving an instance of this class as only argument of private function activeRoutingBehavior(…) instead of 2 immutable args ‘index’ and ‘workers’.
Constructor would stay private also.

Like that :

public class MutableRoundRobin<T> {

  private final ActorRef<T>[] workers;
  private long index;

  private MutableRoundRobin(ActorRef<T>[] workers) {
    this.workers = workers;
  }

  public static <T> Behavior<T> roundRobinBehavior(int numberOfWorkers, Behavior<T> worker) {
    return Behaviors.setup(ctx -> {
      ActorRef<T>[] workers = new ActorRef[numberOfWorkers];
      for (int i = 0; i < numberOfWorkers; i++) {
        workers[i] = ctx.spawn(worker, "worker-" + (i+1));
      }
      return activeRoutingBehavior(new MutableRoundRobin<T>(workers));
    });
  }

  private static <T> Behavior<T> activeRoutingBehavior(final MutableRoundRobin<T> mrr) {
    return Behaviors.immutable((ctx, msg) -> {
      mrr.workers[(int) (mrr.index++ % mrr.workers.length)].tell(msg);
      return Behaviors.same();
    });
  }
}

Something would be wrong with this ?

Renaming Behaviors.immutable() to Behaviors.mutable(), as it is intended to return a behavior hence mutating himself, and having a Behaviors.immutable() that does not need a return, always return same, would not make sense ?


(Johan Andrén) #3

In general the immutable style is somewhat cumbersome to use with OO-style Java and the mutable Java collections, while if using a third party immutable collections library or coming from Scala where the default is to use an immutable collections library it will feel more natural.

One thing to think of is that if you would have a behavior that sends the entire list as a response of some query, then with a mutable collection and a mutable style actor you’d have todo a protective copy and send the copy in the response message to protect against the recipient mutating internal state.

The second solution you came up with, a regular class with state, is not recommended since it will be a risk that the same mutable state is shared across multiple spawned actors. You could however achieve the same by putting that init logic in a lambda using Behaviors.setup to run it on actor start.


#4

Thanks for your answer, so as far I understand the code in sample above is safe, as it is not sharing states.

With java mutable sample here:

You effectively have no risk to share any mutable between actor, but it doesn’t look smart compared to immutable one, just my point of view.

In my sample, you may write mistake, but as the behaviors builder that require a MutableRoundRobin instance is private, the risk of writing buggy sharing state code is limited to this actor class definition…


(Johan Andrén) #5

Ah, yes, missed out that the constructor is private, that should make it safe indeed. The MutableRoundRobin class is the mutable state of the behavior returned with the static factories. That is safe (as long as you don’t share that array elsewhere ofc).


#6

Thanks, in fact I think it may be safer than provided mutable sample from the blog, because this piece of code :

public class MutableRoundRobin<T> extends MutableBehavior<T> {

  private long index = 0;
  ...
 @Override
  public Receive<T> createReceive() {
    return new Actor.Receive<T>() {
      @Override
      public Behavior<T> receiveMessage(T msg) {
      ...
      index++;
     ...
  }

Relies on framework and do not realy prevent to call createReceive() many time on same instance, hence leading to many Receive instances sharing same mutable state. May be that is what already happens in a serialized way under the hood, but that look like a potential weakness.
On the other side, it’s almost 1 year old blog post about an api that is under development…


(Johan Andrén) #7

I think that is an excellent solution in fact, very clean and nice.

We tried to keep the mutable behavior as familiar as possible for Java developers who already know the untyped Actor APIs and comfortable with OO rather than FP, so being able to do inheritance to re-use behaviors/signal handling etc may be valuable enough that we will keep that, but maybe we can also show samples like this for OO-style actors in both Scala and Java.


#8

This is what I understood by seeing that the typed mutable design look like the old untyped one.

I feel that you find a very nice solution for the java typed immutable, far less code to write, better visibility of the whole class content…

As a beginer on this framework, I would say this new way of writing actors is easier to apprehend, and it’s not a luxury. It does not make you want to try the old way anymore. So if it can even lead to better control about state sharing, it should become the recommended way to write a new project in the futur…

I’m still wondering if it still make sense to have a function named Behaviors.immutable() if it’s fine to use it for mutable actors ? Futhermore it should return a Behavior that is expected to mutate himself.


(Johan Andrén) #9

We are renaming that factory and a few others shortly, see https://github.com/akka/akka/issues/24683


#10

Great job again.
Thanks for your time answering my questions, you look very good developers !