4
votes

It is in AKKA documentation written that

... Actors should not block (i.e. passively wait while occupying a Thread) on some external entity, which might be a lock, a network socket, etc. The blocking operations should be done in some special-cased thread which sends messages to the actors which shall act on them. source http://doc.akka.io/docs/akka/2.0/general/actor-systems.html#Actor_Best_Practices

I have found the following information at the moment :

  1. I read Sending outbound HTTP request from Akka / Scala and checked the example at https://github.com/dsciamma/fbgl1

  2. I found following article http://nurkiewicz.blogspot.de/2012/11/non-blocking-io-discovering-akka.html explaining how to use https://github.com/AsyncHttpClient/async-http-client non blocking http client with akka. But is written in Scala.

How can i write an actor that make non-blocking http requests?

It must downlad a remote url page as file and than send the generated file object to the master actor. master actor then sends this request to parser actor to parse the file...

2
async io is usually used on server side, to support thousands of connections with minimal resources. Do you really want to have so many connections in your client program? If not, just run usual synchronous client on a separate thread (examples elsewhere), wait for the file to complete downloading, and send it to the master actor. This is the simplest way, and easy to debug. - Alexei Kaigorodov
I want to write a crawler and run this on many servers. Therefore i want to make it non blocking so that it will be Akka conform. Is it possible to create a seperate thread in actor and send a message to the master when thread completes? - Koray Güclü

2 Answers

4
votes

In the last response, Koray is using a wrong reference for the sender, the correct way to do it is:

public class ReduceActor extends UntypedActor {

@Override
public void onReceive(Object message) throws Exception {
    if (message instanceof URI) {
        URI url = (URI) message;


        AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
        final ActorRef sender = getSender();
        asyncHttpClient.prepareGet(url.toURL().toString()).execute(new AsyncCompletionHandler<Response>() {

            @Override
            public Response onCompleted(Response response) throws Exception {
                File f = new File("e:/tmp/crawler/" + UUID.randomUUID().toString() + ".html");
                // Do something with the Response
                // ...
                // System.out.println(response1.getStatusLine());
                FileOutputStream fao = new FileOutputStream(f);
                IOUtils.copy(response.getResponseBodyAsStream(), fao);
                System.out.println("File downloaded " + f);
                sender.tell(new WordCount(f));
                return response;
            }

            @Override
            public void onThrowable(Throwable t) {
                // Something wrong happened.
            }
        });
    } else
        unhandled(message);
  }

Checkout this other thread of akka: https://stackoverflow.com/a/11899690/575746

0
votes

I have implemented this in this way.

public class ReduceActor extends UntypedActor {
@Override
public void onReceive(Object message) throws Exception {
    if (message instanceof URI) {
        URI url = (URI) message;

        AsyncHttpClient asyncHttpClient = new AsyncHttpClient();

        asyncHttpClient.prepareGet(url.toURL().toString()).execute(new AsyncCompletionHandler<Response>() {

            @Override
            public Response onCompleted(Response response) throws Exception {
                File f = new File("e:/tmp/crawler/" + UUID.randomUUID().toString() + ".html");
                // Do something with the Response
                // ...
                // System.out.println(response1.getStatusLine());
                FileOutputStream fao = new FileOutputStream(f);
                IOUtils.copy(response.getResponseBodyAsStream(), fao);
                System.out.println("File downloaded " + f);
                getSender().tell(new WordCount(f));
                return response;
            }

            @Override
            public void onThrowable(Throwable t) {
                // Something wrong happened.
            }
        });
    } else
        unhandled(message);
}