akka system.shutdown and awaitTermination - akka

Following code is called at the very end of my program (it's written in JRuby):
#na.tell(PoisonPill) if defined? #na # #na, #sa and #pe are Actors
#sa.tell(PoisonPill) if defined? #sa
#pe.tell(PoisonPill) if defined? #pe
##system.shutdown # ##system is the ActorSystem
##system.awaitTermination
I found this approach here but I don't understand why it works.
Does awaitTermination wait for all Actors to terminate?
Isn't ##system shutted down before awaitTermination is called?
edit: I noticed that I doesn't even need to call tell(PoisonPill). I commented it out and it still works...

Okay I solved it now. When I call system.shutdown all actors terminate after their current task. That's not what I want because there could be more tasks in the queue.
So I send a PoisonPill to each actor at the end of my main thread and then wait for them to terminate. I also use the function postStop in each actor to set a finished flag and shut down the system when all actors have finished.
import Actors # needed for Java-style poisonPill
actor1.tell(Actors::poisonPill) # for Akka 2.0.0
actor2.tell(Actors::poisonPill)
system.awaitTermination

Related

When is the ros::shutdown() called for this test_localization_node_bag_pose_tester.cpp of ROS robot_localization package?

How and when does this while loop exit happen in the context of this rostest ?
It exits when ros::ok() returns false
This link explains ros::ok() behaviour:https://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber(c++)
ros::ok() will return false if:
a SIGINT is received (Ctrl-C)
we have been kicked off the network by another node with the same name
ros::shutdown() has been called by another part of the application.
Also test could have timeout defined in test_ekf_localization_node_bag2.test time-limit="1000.0" but I guess it would bypass ros::ok() and kill the node before finishing (you could always test it by modifying timeout)
So in your case I assume you would launch test node, wait until bagfile is finished and exit by Ctrl+C. Unless it exits by itself at the end

Running asynchronous code synchronously in separate thread

I'm using Django Channels to support websockets and am using their concept of a group to broadcast messages to multiple consumers in the same group. In order to send messages outside of a consumer, you need to call asynchronuous methods in otherwise synchronous code. Unfortunately, this is presenting problems when testing.
I began by using loop.run_until_complete:
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.ensure_future(channel_layer.group_send(group_name, {'text': json.dumps(message),
'type': 'receive_group_json'}),
loop=loop))
Then the stacktrace read that the thread did not have an event loop: RuntimeError: There is no current event loop in thread 'Thread-1'.. To solve this, I added:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(asyncio.ensure_future(channel_layer.group_send(group_name, {'text': json.dumps(message),
'type': 'receive_group_json'}),
loop=loop))
And now the stacktrace is reading the RuntimeError: Event loop is closed, although if I add print statements loop.is_closed() prints False.
For context, I'm using Django 2.0, Channels 2, and a redis backend.
Update: I tried running this in a Python interpreter (outside of py.test to remove moving variables). When I ran the second code block, I did not get an Event loop is closed error (that may be due to something on Pytest's end whether its timeouts, etc). But, I did not receive the group message in my client. I did, however, see a print statement:
({<Task finished coro=<RedisChannelLayer.group_send() done, defined at /Users/my/path/to/venv/lib/python3.6/site-packages/channels_redis/core.py:306> result=None>}, set())
Update 2: After flushing redis, I added a fixture in py.test to flush it for every function as well as a session-scoped event loop. This time yielding yet another print from RedisChannelLayer:
({<Task finished coro=<RedisChannelLayer.group_send() done, defined at /Users/my/path/to/venv/lib/python3.6/site-packages/channels_redis/core.py:306> exception=RuntimeError('Task <Task pending coro=<RedisChannelLayer.group_send() running at /Users/my/path/to/venv/lib/python3.6/site-packages/channels_redis/core.py:316>> got Future <Future pending> attached to a different loop',)>}, set())
If channel_layer expects to reside in its own event loop in another thread, you will need to get a hold of that event loop object. Once you have it, you can submit coroutines to it and synchronize with your thread, like this:
def wait_for_coro(coro, loop):
# submit coroutine to the event loop in the other thread
# and wait for it to complete
future = asyncio.run_coroutine_threadsafe(coro, loop)
return future.wait()
wait_for_coro(channel_layer.group_send(group_name, ...), channel_loop)
By default, only the main thread gets an event loop and calling get_event_loop in other threads will fail.
If you need an event loop in another thread -- such as a thread handling an HTTP or WebSockets request -- you need to make it yourself with new_event_loop. After that you can use set_event_loop and future get_event_loop calls will work. I do this:
# get or create an event loop for the current thread
def get_thread_event_loop():
try:
loop = asyncio.get_event_loop() # gets previously set event loop, if possible
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
return loop
More here.

boost async rest client

I currently working on a async rest client using boost::asio::io_service.
I am trying to make the client as a some kind of service for a bigger program.
The idea is that the client will execute async http requests to a rest API, independently from the thread running the main program. So inside in the client will be another thread waiting for a request to send.
To pass the requests to the client I am using a io_service and io_service::work initialized with the io_service. I almost reused the example given on this tutorial - logger_service.hpp.
My problem is that when in the example they post a work to the service, the called handler is a simple function. In my case as I am making async calls like this
(I have done the necessary to run all the instancies of the following objects and some more in a way to be able to establish the network connection):
boost::asio::io_service io_service_;
boost::asio::io_service::work work_(io_service_); //to prevent the io_service::run() to return when there is no more work to do
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_(io_service_);
In the main program I am doing the following calls:
client.Connect();
...
client.Send();
client.Send();
...
Some client's pseudo code:
void MyClass::Send()
{
...
io_service_.post(boost::bind(&MyClass::AsyncSend, this);
...
}
void MyClass::AsyncSend()
{
...
boost::io_service::asio::async_write(socket, streamOutBuffer, boost::bind(&MyClass::handle_send, this));
...
}
void MyClass::handle_send()
{
boost::io_service::asio::async_read(socket, streamInBuffer, boost::bind(&MyClass::handle_read, this));
}
void MyClass::handle_read()
{
// ....treatment for the received data...
if(allDataIsReceived)
FireAnEvent(ReceivedData);
else
boost::io_service::asio::async_read(socket, streamInBuffer, boost::bind(&MyClass::handle_read, this));
}
As it is described in the documentation the 'post' method requests the io_service to invoke the given handler and return immediately. My question is, will be the nested handlers, for example the ::handle_send in the AsyncSend, called just after (when the http response is ready) when post() is used? Or the handlers will be called in another order different from the one defined by the order of post() calls ?
I am asking this question because when I call only once client->Send() the client seems to "work fine". But when I make 2 consecutive calls, as in the example above, the client cannot finish the first call and than goes to execute the second one and after some chaotic executions at the end the 2 operations fail.
Is there any way to do what I'm describing execute the whole async chain before the execution of another one.
I hope, I am clear enough with my description :)
hello Blacktempel,
Thank you for the given comment and the idea but however I am working on a project which demands using asynchronous calls.
In fact, as I am newbie with Boost my question and the example I gave weren't right in the part of the 'handle_read' function. I add now a few lines in the example in a way to be more clear in what situation I am (was).
In fact in many examples, may be all of them, who are treating the theme how to create an async client are very basic... All they just show how to chain the different handlers and the data treatment when the 'handle_read' is called is always something like "print some data on the screen" inside of this same read handler. Which, I think, is completely wrong when compared to real world problems!
No one will just print data and finish the execution of her program...! Usually once the data is received there is another treatment that has to start, for example FireAnEvent(). Influenced by the bad examples, I have done this 'FireAnEvent' inside the read handler, which, obviously is completely wrong! It is bad to do that because making the things like that, the "handle_read" might never exit or exit too late. If this handler does not finish, the io_service loop will not finish too. And if your further treatment demands once again to your async client to do something, this will start/restart (I am not sure about the details) the io_service loop. In my case I was doing several calls to the async client in this way. At the end I saw how the io_service was always started but never ended. Even after the whole treatment was ended, I never saw the io_service to stop.
So finally I let my async client to fill some global variable with the received data inside the handle_read and not to call directly another function like FireAnEvent. And I moved the call of this function (FireAnEvent) just after the io_service.run(). And it worked because after the end of the run() method I know that the loop is completely finished!
I hope my answer will help people :)

Elixir - Basic supervisor setup crashes instead of restarting the child process

Ignoring the absence of the Mix config file, I write the following:
defmodule Test.Supervisor do
use Supervisor
def start_link do
#"name:" will show up in :observer...
Supervisor.start_link(__MODULE__, [], [name: :"root_supervisor"])
end
def init(args) do
children = [
worker(Test.Method, [], [function: :start, id: "my_root_process"]),
]
supervise(children, [strategy: :one_for_one, name: :root])
end
end
defmodule Test do
def start(_type, _args) do
Test.Supervisor.start_link()
end
end
defmodule Test.Method do
def start do
IO.puts("Expect to see me often... #{self}")
end
end
Which crashes after the first run (iex -S mix) without restarting the application. The error message is:
=INFO REPORT==== 14-Jan-2016::22:34:04 ===
application: logger
exited: stopped
type: temporary
** (Mix) Could not start application mememe: Test.start(:normal, {}) returned
an error: shutdown: failed to start child: "my_root_process"
** (EXIT) :ok
If however, I change Test.start() to call Test.Method.start() directly, like so:
defmodule Test do
def start(_type, _args) do
Test.Method.start()
end
end
Then it runs fine, but then the code won't be supervised.
I'm quite sure I'm making an elementary mistake either in implementation, or comprehension here, but what is that mistake exactly?
There are couple of problems with your code. Firstly, you need a long running function to supervise. Something like:
def loop do
receive do
_anything -> IO.puts "Expect to see me often"
end
loop
end
Then in Test.Method module, you have to spawn it.
def start do
IO.puts("Starting...")
pid = spawn_link(&loop/0)
{:ok, pid}
end
It is important, that start function returns tuple {:ok, pid_to_supervise}. It was crashing your app, because supervisor expected a process to monitor, but got only atom :ok returned by IO.puts. Worker specification does not spawn new process. It requires a function, that will return pid of spawned process.
You should also link supervisor to the supervised process, so in the end it might be good idea to rename the function to start_link, instead of start as #Jason Harrelson suggested.
This should be enough to properly start your project. Note, that you will not see your processes in observers Applications section. You are not using Application behaviour, so your root_supervisor will be floating somewhere. You can find it in Processes tab. my_root_process is an id to use withing supervisor, so it won't be visible even in Processes tab.
Spawning process this way is easy for educational purposes, but in real world system, you would like your processes to follow OTP design principles. It means reacting to system messages, better logging, tracing and debugging. Making process that meets all requirements is quite hard, but you don't have to do it manually. All behaviours implement those principles for you.
So instead of spawning a process with loop, try using GenServer.
I would try changing the Test.Method.start function to a Test.Method.start_link function and stop using the function: :start in your opts to the worker function. The supervisor calls start_link by default and there is no reason to break these semantics as the supervisor will always link to the supervised process. If this does not work then at least we have ruled an issue in this area out.

Why are my requests handled by a single thread in spray-http?

I set up an http server using spray-can, spray-http 1.3.2 and akka 2.3.6.
my application.conf doesn't have any akka (or spray) entries. My actor code:
class TestActor extends HttpServiceActor with ActorLogging with PlayJsonSupport {
val route = get {
path("clientapi"/"orders") {
complete {{
log.info("handling request")
System.err.println("sleeping "+Thread.currentThread().getName)
Thread.sleep(1000)
System.err.println("woke up "+Thread.currentThread().getName)
Seq[Int]()
}}
}
}
override def receive: Receive = runRoute(route)
}
started like this:
val restService = system.actorOf(Props(classOf[TestActor]), "rest-clientapi")
IO(Http) ! Http.Bind(restService, serviceHost, servicePort)
When I send 10 concurrent requests, they are all accepted immediately by spray and forwarded to different dispatcher actors (according to logging config for akka I have removed from applicaiton.conf lest it influenced the result), but all are handled by the same thread, which sleeps, and only after waking up picks up the next request.
What should I add/change in the configuration? From what I've seen in reference.conf the default executor is a fork-join-executor, so I'd expect all the requests to execute in parallel out of the box.
From your code I see that there is only one TestActor to handle all requests, as you've created only one with system.actorOf. You know, actorOf doesn't create new actor per request - more than that, you have the val there, so it's only one actor. This actor handles requests sequntially one-by-one and your routes are processing inside this actor. There is no reason for dispatcher to pick-up some another thread, while the only one thread per time is used by only one actor, so you've got only one thread in the logs (but it's not guaranteed) - I assume it's first thread in the pool.
Fork-join executor does nothing here except giving first and always same free thread as there is no more actors requiring threads in parallel with current one. So, it receives only one task at time. Even with "work stealing" - it doesn't work til you have some blocked (and marked to have managed block) thread to "steal" resources from. Thread.sleep(1000) itself doesn't mark thread automatically - you should surround it with scala.concurrent.blocking to use "work stealing". Anyway, it still be only one thread while you have only one actor.
If you need to have several actors to process the requests - just pass some akka router actor (it has nothing in common with spray-router):
val restService = context.actorOf(RoundRobinPool(5).props(Props[TestActor]), "router")
That will create a pool (not thread-pool) with 5 actors to serve your requests.