How to run a daemon forever using Akka Actor? - java

My project is not using Akka as of now, it runs as a single process and does too many things.
As a first inital step, we are trying to put a scaffolding in place so that we get Fault Tolerance. For example,
ProjectSupervisor
|
ExistingProcessActor
Where ExistingProcessActor would run as a forever long running job anf if it gets killed because of some Exception, ProjectSupervisor will restart it
I wasn't too sure about this, so I asked on user-group, and received an interesting advice as
[Me] def run: Unit = LogReaderDisruptor.main(Array())
is a method that is supposed to run forever, plus it required some setup (that is available on client's machine or test environment)
[Advice here] By that do you
mean that the main() is never returning? If so, then you're blocking
the Actor and wasting an entire thread. Spawn this off on a dedicated
dispatcher instead (see dispatchers and futures docs).
I went through the documentation but did not understood what I need to do.
Does that mean following?
ExistingProcessActor will start a new future by giving a custom dispatcher of type PinnedDispatcher?
If so, then in case of any failure how would ProjectSupervisor be notified? He is monitoring ExistingProcessActor and not future (future is not Actor)
I am confused, kindly guide me

You don't need to use a Future in order to have the work done in a dedicated dispatcher. This can be done by spawning an actor and assigning that actor to the dedicated dispatcher. A simple example from the akka docs:
val myActor =
context.actorOf(Props[MyActor].withDispatcher("my-dispatcher"), "myactor1")
http://doc.akka.io/docs/akka/snapshot/scala/dispatchers.html
You could do this within your project supervisor when creating the ExistingProcessActor, putting that actor on a pinned dispatcher, and then your supervision strategy will continue to work as you want.

Related

Is there any difference between Future<Terminated> returned by ActorSystem.terminate() vs ActorSystem.whenTerminated()?

I have my java application uses Akka framework for message routing. During application startup I create Actor System and then creates number of top level actors. Now while shutting down my application, I call Await.result(actorSystem.terminate(), Duration.Inf()) and want my shutdown thread wait till actor system terminates. I came across other API ActorSystem.whenTerminated() which too return Future and does similar stuff.. Just want to know the difference between these two API's? should I use ActorSystem.whenTerminated() instead ?
The future returned by ActorSystem.terminate() is in fact ActorSystem.whenTerminated(), as can be seen in the source code. The only difference is that whenTerminated gives you a future which tells you when the termination has completed, while terminate actually starts the process of termination.
So in a process which is trying to stop the actor system, there's not really a difference between:
scala.compat.java8.FutureConverters.toJava(actorSystem.terminate())
.thenAccept(t -> System.out.println(t))
.join();
and
actorSystem.terminate();
actorSystem.getWhenTerminated()
.thenAccept(t -> System.out.println(t))
.join();
However,
actorSystem.getWhenTerminated()
.thenAccept(t -> System.out.println(t))
.join();
could be anywhere else in the system (e.g. in your main) relative to the terminate call.

Is there an option to fail early in tests when there is no activity?

A simple integration test with Vert.x and JUnit5 might look similar to the following code block.
#Test
#Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
void some_test(Vertx vertx, VertxTestContext testContext) {
// do nothing in this example.
}
This simple test will wait for 10 seconds and then fail due to the timeout. I want to know if there is an option to fail this tests early without waiting for the timeout. Since there is no activity, Vert.x could infer that the test will never be complete if it isn't already. With no activity, I mean that there are no running tasks nor timers. Only external operations could cause further actions but I imagine that many tests don't have such external triggers.
I would like to know if Vert.x provides the possibility to say "There are no external triggers. Just stop when there is nothing left to do."
Vert.x is reactive which means that your implementation reacts on the events that other actors send over the event bus.
Normally, the only thing you can do is listen on the event bus. Your implementation cannot decide if the non-existence of external events is some kind of error. If the other actors have nothing to say, it can be a non-erroneous condition.
To decide if there are no external triggers and to fail the test early if nothing is left to do, can only be accomplished by gaining insights on the internal state of all other actors.
One could argue that this is not the task of a unit test, as other actors can be considered not being part of your unit.
A suggestion for a solution
All of your other actors (i.e. verticles) could at one point emit an event notifying your test-implementation, that they have finished their work and have nothing left to do.
Your test could count those finished events and act itself accordingly by calling testContext.completeNow();, as soon as it has received all finished events.
As far as I know, there is no option or tool in the vert.x-toolkit or junit to do this work for you. You would have to implement it yourself.

Processing methods/threads in correct order

I have an application that is quite complex (it's a command and control center spring + angular based application that is meant to be used by police and other emergency center controllers).
Main component of application (lets call it backbone [spring web app]) is communication with different applications/hardware. Most of that communication is done by using RabbitMQ messages (lets call them telegrams or in short TMs).
When one of that TMs is received by backbone new thread is created and in it some method/methods is/are executed.
The problem is that it can happen that backbone receives two or more TMs almost at the same time, and since they are executed in different threads it can happen that they are not finessed in same order as they arrived and hence wrong information is presented to the user.
Usually, problems like this I handle with Redis. I have a redis lock that basically looks like this
distributedRedisLocker.lock(() -> {
executeSomeMethod();
}, howLongIsLockKept, howLongDoWeWaitForItToFinnish);
But in this case I would like to avoid using redis, is there any other java/spring based solution to this?
I do not need it to be same as redis lock that I have, only what I want is that TMs are proccessed in order they arrive, and if one of them fails somewhere in method execution that it does not block the next one forever.
Reposting as an answer.
One way to solve your problem is to avoid concurrency. You could use Executors.newSingleThreadExecutor() which only uses one thread:
ExecutorService executor = Executors.newSingleThreadExecutor();
and then
executor.execute(...);
or
executor.submit(...);
This would help you avoid races: if some TM A is added to execution queue defined by this executor before some TM B, then A will be executed before B as a whole.
Also, no explicit locks are involved (apart from implicit ones that can be contained inside the executor implementation, but they are encapsulated and will not stay handing forever in case of an error).
There is a subtle moment: if two TMs arrive at the same time, it's impossible to predict which will be added earlier and which later.

How to restrict the akka actor to do one job at a time

I have an Java-Akka based application where one Akka actor tells another Akka actor to do a certain jobs and it starts doing the job in the command prompt but If I gave him 10 jobs it starts all the jobs at a time in 10 command prompt.
If i'll be having 100+ jobs than my system will be hanged.
So how can I make my application to do the job 1 at a time and all the other jobs should will get the CPU in FIFO(first in first out) manner.
The question is not quite clear but I try to answer with my understanding.
So, it looks like you use actor as a job dispatcher which translates job messages to calls for some "job executor system". Each incoming message is translated to some call.
If this call is synchronous (which smells when working with actors of course but just for understanding) then no problem in your case, your actor waits until call is complete, then proceed with next message in its mailbox.
If that call is asynchronous which I guess what you have then all the messages will be handled one by one without waiting for each other.
So you need to throttle the messages handling in order to have at most one message being processed at a time. This can be archived by "pull" pattern which is described here.
You basically allocate one master actor which has a queue with incoming messages (jobs) and one worker actor which asks for job when it is free of jobs. Be careful with the queue in master actor - you probably don't want it to grow too much, think about monitoring and applying back-pressure, which is another big topic covered by akka-stream.

Java Async Processing

I am currently developing a system that uses allot of async processing. The transfer of information is done using Queues. So one process will put info in the Queue (and terminate) and another will pick it up and process it. My implementation leaves me facing a number of challenges and I am interested in what everyone's approach is to these problems (in terms of architecture as well as libraries).
Let me paint the picture. Lets say you have three processes:
Process A -----> Process B
|
Process C <-----------|
So Process A puts a message in a queue and ends, Process B picks up the message, processes it and puts it in a "return" queue. Process C picks up the message and processes it.
How does one handle Process B not listening or processing messages off the Queue? Is there some JMS type method that prevents a Producer from submitting a message when the Consumer is not active? So Process A will submit but throw an exception.
Lets say Process C has to get a reply with in X minutes, but Process B has stopped (for any reason), is there some mechanism that enforces a timeout on a Queue? So guaranteed reply within X minutes which would kick off Process C.
Can all of these matters be handled using a dead letter Queue of some sort? Should I maybe be doing this all manually with timers and check. I have mentioned JMS but I am open to anything, in fact I am using Hazelcast for the Queues.
Please note this is more of a architectural question, in terms of available java technologies and methods, and I do feel this is a proper question.
Any suggestions will be greatly appreciated.
Thanks
IMHO, The simplest solution is to use an ExecutorService, or a solution based on an executor service. This supports a queue of work, scheduled tasks (for timeouts).
It can also work in a single process. (I believe Hazelcast supports distributed ExecutorService)
It seems to me that the type of questions you're asking are "smells" that queues and async processing may not be the best tools for your situation.
1) That defeats a purpose of a queue. Sounds like you need a synchronous request-response process.
2) Process C is not getting a reply generally speaking. It's getting a message from a queue. If there is a message in the queue and the Process C is ready then it will get it. Process C could decide that the message is stale once it gets it, for example.
I think your first question has already been answered adequately by the other posters.
On your second question, what you are trying to do may be possible depending on the messaging engine used by your application. I know this works with IBM MQ. I have seen this being done using the WebSphere MQ Classes for Java but not JMS. The way it works is that when Process A puts a message on a queue, it specifies the time it will wait for a response message. If Process A fails to receive a response message within the specified time, the system throws an appropriate exception.
I do not think there is a standard way in JMS to handle request/response timeouts the way you want so you may have to use platform specific classes like WebSphere MQ Classes for Java.
Well, kind of the point of queues is to keep things pretty isolated.
If you're not stuck on any particular tech, you could use a database for your queues.
But first, a simple mechanism to ensure two processes are coordinated is to use a socket. If practical, simply have process B create an open socket listener on some well know port, and process A will connect to that socket, and monitor it. If process B ever goes away, process A can tell because their socket gets shutdown, and it can use that as an alert of problems with process B.
For the B -> C problem, have a db table:
create table queue (
id integer,
payload varchar(100), // or whatever you can use to indicate a payload
status varchar(1),
updated timestamp
)
Then, Process A puts its entry on the queue, with the current time and a status of "B". B, listens on the queue:
select * from queue where status = 'B' order by updated
When B is done, it updates the queue to set the status to "C".
Meanwhile, "C" is polling the DB with:
select * from queue where status = 'C'
or (status = 'B' and updated < (now - threshold) order by updated
(with the threshold being however long you want things to rot on the queue).
Finally, C updates the queue row to 'D' for done, or deletes it, or whatever you like.
The dark side is there is a bit of a race condition here where C might try and grab an entry while B is just starting up. You can probably get through that with a strict isolation level, and some locking. Something as simply as:
select * from queue where status = 'C'
or (status = 'B' and updated < (now - threshold) order by updated
FOR UPDATE
Also use FOR UPDATE for B's select. This way whoever win the select race will get an exclusive lock on the row.
This will get you pretty far down the road in terms of actual functionality.
You are expecting the semantics of synchronous processing with async (messaging) setup which is not possible. I have worked on WebSphere MQ and normally when the consumer dies, the messages are kept in the queue forever (unless you set the expiry). Once the queue reaches its depth, the subsequent messages are moved to the dead letter queue.
I've used a similar approach to create a queuing and processing system for video transcoding jobs. Basically the way it worked was:
Process A posts a "schedule" message to Arbiter Q, which adds the job into its "waiting" queue.
Process B requests the next job from Arbiter Q, which removes the next item in its "waiting" queue (subject to some custom scheduling logic to ensure that a single user couldn't flood transcode requests and prevent other users from being able to transcode videos) and inserts it into its "processing" set before returning the job back to Process B. The job is timestamped when it goes into the "processing" set.
Process B completes the job and posts a "complete" message to Arbiter Q, which removes the job from the "processing" set and then modifies some state so that Process C knows the job completed.
Arbiter Q periodically inspects the jobs in its "processing" set, and times out any that have been running for an unusually long amount of time. Process A is then free to attempt to queue up the same job again, if it wants.
This was implemented using JMX (JMS would have been much more appropriate, but I digress). Process A was simply the servlet thread which responded to a user-initiated transcode request. Arbiter Q was an MBean singleton (persisted/replicated across all the nodes in a cluster of servers) that received "schedule" and "complete" messages. Its internally managed "queues" were simply List instances, and when a job completed it modified a value in the application's database to refer to the URL of the transcoded video file. Process B was the transcoding thread. Its job was simply to request a job, transcode it, and then report back when it finished. Over and over again until the end of time. Process C was another user/servlet thread. It would see that the URL was available, and present the download link to the user.
In such a case, if Process B were to die then the jobs would sit in the "waiting" queue forever. In practice, however, that never happened. If your Process B is not running/doing what it is supposed to do then I think that suggests a problem in your deployment/configuration/implementation of Process B more than it does a problem in your overall approach.

Categories