Akka a vzdialené volanie aktorov pre otáčanie reťazcov

Akka vo svojej dokonalosti aktorového frameworku môže poslúžiť aj ako nástroj pre vzdialené volanie procedúr.

Aha, príklad otáčača reťazcov.

Potrebujeme:

  • akka-actor_2.10-2.2.3.jar
  • scala-library.jar (verzie 2.10)
  • protobuf-java-2.4.1.jar
  • config-1.0.2.jar
  • akka-remote_2.10-2.2.3.jar
  • netty-3.6.6.Final.jar

Posledné dva JARy potrebujeme kvôli remotingu.

Server

Aktor

Aktor pre otáčanie prijme jeden reťazec a vráti odosielateľovi otočený reťazec.

package sk.upjs.ics.novotnyr.akka;

import akka.actor.UntypedActor;

public class StringReversingActor extends UntypedActor {

    @Override
    public void onReceive(Object message) throws Exception {
        if(message instanceof String) {
            String inputString = (String) message;
            String result = reverse(inputString);

            sender().tell(result, getSelf());
        } else {
            unhandled(message);
        }
    }

    private String reverse(String string) {
        return new StringBuilder(string).reverse().toString();
    }

}

Reťazce nie sú ideálne typy pre správy (Akka odrádza od používania základných typov), ale pre jednoduchosť budú stačiť. Dôležité je, že sú nemenné (immutable) a serializovateľné (implementujú java.io.Serializable).

Konfigurácia

package sk.upjs.ics.novotnyr.akka;

import akka.actor.ActorSystem;
import akka.actor.Props;

import com.typesafe.config.ConfigFactory;

public class Server {
    public static void main(String[] args) throws Exception {
        ActorSystem system = ActorSystem.create("StringReversingSystem", ConfigFactory.load("server.conf"));
        system.actorOf(Props.create(StringReversingActor.class), "StringReverse");
    }
}

Vytvoríme systém s názvom StringReversingSystem a vytvoríme v ňom aktora s logickým menom StringReverse: tie sa totiž objavia vo výslednej URL koncového bodu.

Konfiguráciu načítame zo súboru server.conf

akka {
    actor {     
        provider = "akka.remote.RemoteActorRefProvider" 
    }

    remote {
        netty.tcp {
            hostname = "127.0.0.1"
            port = 2553
        }
    }       
}
  • V konfigurácii zapneme poskytovateľa pre volanie vzdialených aktorov.
  • Nastavíme hostiteľa, na ktorom pobežíme (buď IPčkou alebo názvom servera)
  • Nastavíme port. Defaultne 2552, ale predefinujeme ho, aby sme sa nezrazili s portom pre klienta.
  • Remoting pobeží na asynchrónnej knižnici Netty nad TCP protokolom.

Celá konfigurácia zverejní aktora na adrese:

akka.tcp://StringReversingSystem@127.0.0.1:2553/user/StringReverse

Klient

Najprv si dajme konfiguráciu

Súbor client.conf:

akka {
  actor {
    provider = "akka.remote.RemoteActorRefProvider"
  }
}

Žiadna zložitosť, len zapneme podporu pre vzdialených aktorov.

Aj keď pozor: štandardne sa aktorový systém klienta tiež spustí na konkrétnom porte: v tomto prípade na štandardom 2552. To je dôvod, prečo sme na serveri zvolili iný port než na klientovi: pre lokálne spúšťaný server aj klient by sme inak uvideli BindException indikujúci, že máme pokus o spustenie dvoch služieb na jednom porte.

Java kód

package sk.upjs.ics.novotnyr.akka;

import scala.concurrent.Future;
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.dispatch.OnSuccess;
import akka.pattern.Patterns;

import com.typesafe.config.ConfigFactory;

public class Client {
    public static void main(String[] args) {
        ActorSystem actorSystem = ActorSystem.create("client", ConfigFactory.load("client.conf"));
        ActorSelection calculator = actorSystem.actorSelection("akka.tcp://StringReversingSystem@158.197.31.121:2553/user/StringReverse");

        Duration duration = Duration.create(2, TimeUnit.SECONDS);
        Future<Object> future = Patterns.ask(calculator, "mor dni lape je palindrom", duration.toMillis());
        Object result = Await.result(future, duration);
        System.out.println(result);
        actorSystem.shutdown();
    }
}
  • Vytvoríme ďalší aktorový systém pre klienta podľa konfiguráku client.conf.
  • Vytiahneme vzdialeného aktora cez actorSelection, kde za identifikátor použijeme celú URL adresu.
    • V starých Akkách sa používala metóda actorFor(), ktorá síce nerobila na povrchu rozdiel medzi lokálnym a vzdialeným aktorom, ale správala sa odlišne a vracala odlišné hodnoty. Podrobnosti viď dokumentácia.
  • Vytvoríme dvojsekundové obdobie použité pre dve veci:
    • čakanie na odpoveď od vzdialeného aktora (pattern ask)
    • a na získanie výsledku z Future, ktorý bude obsahovať výsledok
  • Pri čakaní na výsledok využívame blokovanie, čo je v Akke veľmi zlé, ale keďže ide o demonštračný spúšťač, je to odpustiteľné. (Čakáme totiž na výsledok jednorazovej operácie, po ktorej celá aplikácia skončí.)

To je všetko!

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *