I have a ServiceFabric Actor that is responsible for processing turn-by-turn requests sent to it to check whether inventory is available or not.
These requests are sent to a Stateful Service which checks if inventory is available or not, and returns a true/false accordingly (among other things it does).
In order to get this to work right, I need the ability to pass the inventoryId when the Actor is activated (or initialized?) so that it can also initialize/activate the Stateful Service to load up the Inventory quota and related info from the database.
How can I pass the parameters to the Actor and Stateful service in a constructor? I am currently resorting to passing the inventory Id in each call to the actor and always checking if Service is initialized or not. That is becoming redundant as I add more and more methods.
Any thoughts?
Maybe you can use the inventoryId as the ActorId for the Actor that manages the lifecycle of the service. (So one Actor instance for every inventoryId.)
The Actor can then be used to initialize the service with the inventoryId as well.
Finally, the Actor can be used to return the information required to create a proxy to call the service (service name and likely partition information).
Related
I am using Kogito with Quarkus. I have set on drl rule and am using a bpmn configuration. As can be seen below, currently one endpoint is exposed, that starts the process. All needed data is received from the initial request, it is then evaluated and process goes on.
I would like to extend the workflow to have two separate endpoints. One to provide the age of the person and another to provide the name. The process must wait until all needed data is gathered before it proceeds with evaluation.
Has anybody come across a similar solution?
Technically you could use a signal or message to add more data into a process instance before you execute the rules over the entire data, see https://docs.kogito.kie.org/latest/html_single/#ref-bpmn-intermediate-events_kogito-developing-process-services.
In order to do that you need to have some sort of correlation between these events, otherwise, how do you map that event name 1 should be matched to event age 1. If you can keep the process instance id, then the second event can either trigger a rest endpoint to the specific process instance or send it a message via a message broker.
You also have your own custom logic to aggregate the events and only fire a new process instance once your criteria of complete data is met, and there is also plans in Kogito to extend the capabilities of how correlation is done, allowing for instance to use variables of the process as the identifier. For example, if you have person.id as correlation and event to name and age of the same id would signal the same process instance. HOpe this info helps.
In a ServiceFabric app, I have the necessity to create thousands of stateful Actors, so I need to avoid accumulating Actors when they become useless.
I know I can't delete an Actor from the Actor itself, but I don't want to keep track of Actors and loop to delete them.
The Actors runtime use Garbace collection to remove the deactivated Actor objects (but not their state); so, I was thinking about removing Actor state inside the OnDeactivateAsync() method and let the GC deallocate the Actor object after the usual 60min.
In theory, something like this should be equivalent to delete the Actor, isn't it?
protected override async Task OnActivateAsync()
{
await this.StateManager.TryRemoveStateAsync("MyState");
}
Is there anything remaining that only explicit deletion can remove?
According to the docs, you shouldn't change the state from OnDeactivateAsync.
If you need your Actor to not keep persisted state, you can use attributes to change the state persistence behavior:
No persisted state: State is not replicated or written to disk. This
level is for actors that simply don't need to maintain state reliably.
[StatePersistence(StatePersistence.None)]
class MyActor : Actor, IMyActor
{
}
Finally, you can use the ActorService to query Actors, see if they are inactive, and delete them.
TL;DR There are some additional resources you can free yourself (reminders) and some that only explicit deletion can remove because they are not publicly accessible.
Service Fabric Actor repo is available on GitHub. I am using using persistent storage model which seems to use KvsActorStateProvider behind the scenes so I'll base the answer on that. There is a series of calls that starts at IActorService.DeleteActorAsync and continues over to IActorManager.DeleteActorAsync. Lot of stuff is happening in there including a call to the state provider to remove the state part of the actor. The core code that handles this is here and it seems to be removing not only the state, but also reminders and some internal actor data. In addition, if you are using actor events, all event subscribers are unsubscribed for your actor.
If you really want delete-like behavior without calling the actor runtime, I guess you could register a reminder that would delete the state and unregister itself plus other reminders.
Azure Service Fabric documentation says that:
Actors provide flexibility for the developer to define rich object
structures as part of the actors or reference object graphs outside of
the actors. In caching terms actors can write-behind or write-through,
or we can use different techniques at a member variable granularity.
In terms of a StatefulActor or StatefulActor<T>, how would one go about implementing write-behind to improve throughput of state-changing methods?
A possible implementation would be to mark your mutation method as [Readonly], so that the service fabric runtime would not persist the State to the cluster replicas. You could therefore modify in memory member variables with the change that you have described and success or failure will be quickly returned to the calling code. At the same time as modifying the member variables, you would register a reminder that will modify the State property and hence asynchronously distribute the change across the replicas in the cluster.
You would need to consider the possibility of the actor being moved to a different node before the reminder fires, resulting in read calls to return stale data read from the State property before the gets updated.
I'm looking for suggestions on how to accomplish the following. My Akka application, which will be running as a cluster, will be persisting to a backend web service. Each resource I'm persisting is named. For example: A, B, C
There will be a queue of changes for each resource, and I'm looking for an idea on how I can have a configuration which allows me to control the following:
Maximum number of REST calls in progress at any point in time (overall concurrency)
Ensure that only one REST request for each named resource is in progress
It's fine for concurrent requests, as long as they are not for the same resource
The named resources are dynamic, based on records in a database
Thanks
My vision is next:
You need to have some kind of supervisor actor which maintains some state. On each request to this supervisor you check wheather you have this resource been currently processing. If yes, then you should store this request to some storage/queue. If no, spawn new actor and put this actor and the resource to the mentioned state. On completion, remove the actor and resource from the state. I strongly recommend you to have storage/queue to temporarily save request to supervisor actor. In such case you protect yourself from overwhelming the system. To guarantee overall concurrency requirement you may make internal state of supervisor bounded and if the size exceeds you store request to storage/queue.
Of course you need some mechanism of polling this queue and make requests to supervisor
Suppose I have an application that uses actors for processing User. So there is one UserActor per user. Also every user Actor is mapped to user via id, e.g. to process actions with concrete user you should get Actor like that:
ActorSelection actor = actorSystem.actorSelection("/user/1");
where 1 is user id.
So the problem is - how generate unique id inside cluster effectively? First it needs to check that new id will not duplicate an existent one. I can create one actor for generating id's which will live in one node, and before creating any new UserActor Generator is asked for id, but this leads to additional request inside cluster whenever user is created. Is there a way to do this more effective? Are there build-in akka techniques to do that?
P.S. May this architecture for using Actor is not effective any suggestion/best practice is welcome.
I won't say whether or not your approach is a good idea. That's going to be up to you to decide. If I do understand your problem correctly though, then I can suggest a high level approach to making it work for you. If I understand correctly, you have a cluster, and for any given userId, there should be an actor in the system that handles requests for it, and it should only be on one node and consistently reachable based on the user id of the user. If that's correct, then consider the following approach.
Let's start first with a simple actor, let's call it UserRequestForwarder. This actors job is to find an actor instance for a request for a particular user id and forward on to it. If that actor instance does not yet exist, then this actor will create it before forwarding onto it. A very rough sketch could look like this:
class UserRequestForwarder extends Actor{
def receive = {
case req # DoSomethingForUser(userId) =>
val childName = s"user-request-handler-$userId"
val child = context.child(childName).getOrElse(context.actorOf(Props[UserRequestHandler]))
child forward req
}
}
Now this actor would be deployed onto every node in the cluster via a ConsistentHashingPool router configured in such a way that there would be one instance per node. You just need to make sure that there is something in every request that needs to travel through this router that allows it to be consistently hashed to the node that handles requests for that user (hopefully using the user id)
So if you pass all requests through this router, they will always land on the node that is responsible for that user, ending up in the UserRequestForwarder which will then find the correct user actor on that node and pass the request on to it.
I have not tried this approach myself, but it might work for what you are trying to do provided I understood your problem correctly.
Not an akka expert, so I can't offer code, but shouldn't the following approach work:
Have a single actor being responsible for creating the actors. And have it keep a Hashset of actor names, for actors that it created, and that didn't die already.
If you have to spread the load between multiple actors you can dispatch the task based on the first n digits of the hashcode of the actor name that has to be created.
It seems like you have your answer on how to generate the unique ID. In terms of your larger question, this is what Akka cluster sharding is designed to solve. It will handle distributing shards among your cluster, finding or starting your actors within the cluster and even rebalancing.
http://doc.akka.io/docs/akka/2.3.5/contrib/cluster-sharding.html
There's also an activator with a really nice example.
http://typesafe.com/activator/template/akka-cluster-sharding-scala