How to limit actors per user - scala

I am trying to understand how I could model this with akka.
My system processes messages for users, and the messages have to be processed serially for each user i.e. I cannot have 2+ actors processing a message at the same time for the same user.
So if I get 100 messages, and they are all for different users, I can spawn as many actors as I need to handle them.
But if I get 100 messages and they are for only 10 users, I have to ensure there is only 1 actor processing a given user at the same time.
How could I model this in Akka? How could I filter messages or manage that only 1 actor per user?
note: Each message will have a UserId with it.

Based on the information given, it sounds like you should consider using Cluster Sharding, and shard based on the user id. There are other solutions too, but this is probably a good fit and very simple to add based on what you've described.

One approach would be to have a map between user id and its actor in your request accepting actor. As such, every actor has a mailbox, so that it will queue the incoming messages to a certain extent (it's up to you to set up the mailbox size, it can even be unlimited, as far as memory allows).
In other words,
class RequestAcceptor extends Actor {
var users: Map[UserId, ActorRef] = Map.empty
def receive = {
case r#UserRequest(userId) =>
val maybeActor = users.get(userId)
if (maybeActor.isDefined) {
maybeActor.get ! r
} else {
val actor = Props(classOf[ProcessingActor])
users += userId -> actor
actor ! r
}
}
}
Of course, you have to take care about the mailbox overflow in this case, but that would be a separate question, which is most probably should better be solved with Akka Streams.

Related

Can an Akka Actor Handle Multiple Message Types in Akka Typed

Is it possible to handle multiple message types from a single actor.
For example, assume there is an actor called TradingStrategy that trades stocks. It takes in pricing data pumped in from another Actor. When it decides to place a trade, it sends a message to an another Actor, call it OrderActor, to place a trade. But the TradingStrategy Actor is interested in knowing whether or not the order placed was successful or rejected, etc... because it may change its strategy based on the results from the place order action. In this example, it seems the TradingStrategy needs to handle messages for pricing updates AND order updates. Is this possible with Akka typed? Are there ways to handle this situation?
Here is a code example:
IEXData is the data message.
def apply(orderActor: ActorRef[OrderCommand]): Behavior[IEXData] = Behaviors.setup { context =>
new SimpleTradingStrategy(context, brokerActor)
}
}
class SimpleTradingStrategy(
context: ActorContext[IEXData],
orderActor: ActorRef[OrderCommand],
ticker: Ticker = "spy"
) extends AbstractBehavior[IEXData](context) {
TradingStrategy's protocol would have to include messages indicating order updates. A TradingStrategy actor can register a message adapter which will translate the messages sent by the order actor into TradingStrategy's protocol: the TradingStrategy can present the "virtual" ActorRef returned by the message adapter to the order actor without the order actor knowing that its a TradingStrategy.

Find actor by persistence id

I have a system, that has an actor per user. Users send messages rarely, but when they do, they send usually not only one, but few.
Currently, I have a map, where I store persistenceId -> ActorRef. When I'm receiving a new message for an actor, I look into the map, if there is an ActorRef, I use it. If it is missing, I create it and put it into the map. For sure I don't want to have 2 instances of same persistence actor at the same time. Also, I don't want to create and destroy the actor for each message, as recovery could take some time.
I feel there should be some cleaner way of "locating or creating" an actor. Something like actorSystem.getOrCreate(persistenceId, props). I thought that sharding might help me with that, but I couldn't find an exact example of this. Also, I know there is actorSelection, which has downsides:
using it in too many places, with hardcoded paths that are tricky to
maintain
using it to send too many messages as it has a performance
cost
So basically the question is what is the best way of locating persistence actor within one service if I actor persistenceId is userId. If I decide to use sharding, then it will be 1 shard per actor. Is this ok?
Actor sharding is pretty much what you need - you can think about it as a distributed map of actors and there is no need of having additional solutions. The sharding takes care of summoning the actor behind the scenes and there is no need for you to manage actors yourself.
val sharding = ClusterSharding(system).start(
typeName = CustomerActor.shardName,
entityProps = CustomerActor.props,
settings = ClusterShardingSettings(system),
extractEntityId = CustomerActor.extractEntityId,
extractShardId = CustomerActor.extractShardId)
}
where extractEntityId is a function which routes messages to appropriate actors
val extractEntityId: ShardRegion.ExtractEntityId = {
case gc: GetCustomer => (gc.customerId, gc)
}
And final example:
case class GetCustomer(customerId: String)
sharding ! GetCustomer("customer-id")
More details here https://doc.akka.io/docs/akka/2.5/cluster-sharding.html

Broadcast message to actors watching a particular actor?

How can I broadcast a message to all actors that are watching a particular actor?
For context, suppose I have a AuctionActor (which is potentially a remote actor) that is being watched by a large number of AuctionParticipantActor types. I would like the AuctionActor to broadcast various messages to AuctionParicipantActor types.
One possibility would be for the AuctionActor to keep a collection of all participant ActorRef instances and then loop over this collection when ever a message needs to be sent to all participants. This seems inefficient and I am hoping for a better solution...
If you don't want to go with PubSub as mentioned by Diego Martinoia, I would suggest using Routers with BroadcastingLogic. This goes in the direction you mentioned with the collection of ActorRefs, but uses Akka functionality to achieve it being more efficient than just iterating over a collection in your AuctionActor.
From Akka Docs
Routers are designed to be extremely efficient at receiving messages and passing them quickly on to routees.
A normal actor can be used for routing messages, but an actor’s single-threaded processing can become a bottleneck. Routers can achieve much higher throughput with an optimization to the usual message-processing pipeline that allows concurrent routing.
In your case it could look like this:
class AuctionActor extends Actor {
var router = Router(BroadcastRoutingLogic(), Vector[ActorRefRoutee]())
def receive = {
case AddParticipant(ref) =>
router = router.addRoutee(ref)
case RemoveParticipant(ref) =>
router = router.removeRoutee(ref)
case update: ImportantUpdate =>
router.route(update, self)
}
}

Avoid concurrent execution of Akka actor

I'm currently sending a message to an Akka actor every second for it to perform a task.
If that task (function) is still running when a new message is received by the actor, I would like the actor to do nothing. Basically, I want the actor function to be run only if it's not already running.
What's a good way to do this? Should I use Akka actors or do it another way?
Cheers
Actors process a message at a time. The situation you describe cannot happen.
Akka actors process their messages asynchronously one-by-one, so you can only drop/ignore "expired" messages to avoid extra processing and OutOfMemoryException-s due to actor's Mailbox overflow.
You can ignore expired (more than 1 second old in your case) messages inside your actor:
case class DoWork(createdTime: Long = System.currentTimeMillis)
final val messageTimeout = 1000L // one second
def receive = {
case DoWork(createdTime) =>
if((System.currentTimeMillis - createdTime) < messageTimeout) { doWork() }
}
Or you can create a custom Mailbox which can drop expired messages internally.
Of course, as Robin Green already mentioned, actors in general are not supposed to run long-running operations internally so this approach can be suitable only if your actor doesn't need to process other kind of messages (they will not be processed in time). And in case of high CPU demands you may consider to move your actor on a separate dispatcher.

An Actor "queue"?

In Java, to write a library that makes requests to a server, I usually implement some sort of dispatcher (not unlike the one found here in the Twitter4J library: http://github.com/yusuke/twitter4j/blob/master/twitter4j-core/src/main/java/twitter4j/internal/async/DispatcherImpl.java) to limit the number of connections, to perform asynchronous tasks, etc.
The idea is that N number of threads are created. A "Task" is queued and all threads are notified, and one of the threads, when it's ready, will pop an item from the queue, do the work, and then return to a waiting state. If all the threads are busy working on a Task, then the Task is just queued, and the next available thread will take it.
This keeps the max number of connections to N, and allows at most N Tasks to be operating at the same time.
I'm wondering what kind of system I can create with Actors that will accomplish the same thing? Is there a way to have N number of Actors, and when a new message is ready, pass it off to an Actor to handle it - and if all Actors are busy, just queue the message?
Akka Framework is designed to solve this kind of problems, and is exactly what you're looking for.
Look thru this docu - there're lots of highly configurable dispathers (event-based, thread-based, load-balanced, work-stealing, etc.) that manage actors mailboxes, and allow them to work in conjunction. You may also find interesting this blog post.
E.g. this code instantiates new Work Stealing Dispatcher based on the fixed thread pool, that fulfils load balancing among the actors it supervises:
val workStealingDispatcher = Dispatchers.newExecutorBasedEventDrivenWorkStealingDispatcher("pooled-dispatcher")
workStealingDispatcher
.withNewThreadPoolWithLinkedBlockingQueueWithUnboundedCapacity
.setCorePoolSize(16)
.buildThreadPool
Actor that uses the dispatcher:
class MyActor extends Actor {
messageDispatcher = workStealingDispatcher
def receive = {
case _ =>
}
}
Now, if you start 2+ instances of the actor, dispatcher will balance the load between the mailboxes (queues) of the actors (actor that has too much messages in the mailbox will "donate" some to the actors that has nothing to do).
Well, you have to see about the actors scheduler, as actors are not usually 1-to-1 with threads. The idea behind actors is that you may have many of them, but the actual number of threads will be limited to something reasonable. They are not supposed to be long running either, but rather quickly answering to messages they receive. In short, the architecture of that code seems to be wholly at odds with how one would design an actor system.
Still, each working actor may send a message to a Queue actor asking for the next task, and then loop back to react. This Queue actor would receive either queueing messages, or dequeuing messages. It could be designed like this:
val q: Queue[AnyRef] = new Queue[AnyRef]
loop {
react {
case Enqueue(d) => q enqueue d
case Dequeue(a) if q.nonEmpty => a ! (q dequeue)
}
}