統合Akka

10832 ワード

Integrating with Akka


Akkaは、Actorモデルを使用して抽象レベルを向上させ、適切な同時および拡張可能なアプリケーションを構築するためのより良いプラットフォームを提供します.フォールトトレランスにはLet it crashモデルを採用し,これは電気通信業界で永遠に停止しない自己治癒システムを構築するのに成功した応用である.Actorはtransparent distributionと基本的な本当に拡張可能でフォールトトレランスの応用を提供した.

The application actor system


Akkaはactor systemsと呼ばれるいくつかの容器を使用することができます.1つのactor systemは、その構成リソースを管理して、彼が含むactorsを実行する.
1つのPlayアプリケーションは、特殊なactorシステムが自身で使用されることを定義する.このactor systemは、このアプリケーションのライフサイクルに従って自動的に再起動され、アプリケーションが再起動されると自動的に再起動されます.

Writing actors


Akkaを使うにはactorを書く必要があります次は簡単なactorです.
package actors;

import akka.actor.*;
import actors.HelloActorProtocol.*;

public class HelloActor extends UntypedActor {

    public static Props props = Props.create(HelloActor.class);

    public void onReceive(Object msg) throws Exception {
        if (msg instanceof SayHello) {
            sender().tell("Hello, " + ((SayHello) msg).name, self());
        }
    }
}

ここでHelloActorは、propsというstatic fieldを定義し、このactorの作成方法を記述するためにPropsオブジェクトを返します.これは、actorを作成するコードからインスタンス化された論理を分離するための非常に良いAkka慣例です.
ここにbest practiceがあります.HelloActorの送信と受信をstatic inner classesと定義することをHelloActorProtocolと呼びます.
package actors;

public class HelloActorProtocol {

    public static class SayHello {
        public final String name;

        public SayHello(String name) {
            this.name = name;
        }
    }
}

Creating and using actors

actorを作成または使用するには、ActorSystemが必要です.依存性を明らかにすることで得ることができ、actorOfの方法で新しいactorを作成することができます.
最も基本的なことはactorにmessageを送ることですメッセージをactorに送信すると応答しませんこれもtellモードと呼ぶ.
しかしながら、1つのウェブアプリケーションでは、HTTPプロトコルはrequestおよびresponsesであるため、tellモードは通常は役に立たない.この場合、askモードが望ましいかもしれません.このaskモードはScalaのFutureを返し、scala.compat.java8.FutureConverts.toJavaを使用してJavaのCompletionStageに変換することができます.askモードを使用したHelloActorの例を次に示します.
import akka.actor.*;
import play.mvc.*;
import scala.compat.java8.FutureConverters;
import javax.inject.*;
import java.util.concurrent.CompletionStage;

import static akka.pattern.Patterns.ask;//need imported

@Singleton
public class Application extends Controller {

    final ActorRef helloActor;

    @Inject public Application(ActorSystem system) {
        helloActor = system.actorOf(HelloActor.props);
    }

    public CompletionStage sayHello(String name) {
        return FutureConverters.toJava(ask(helloActor, new SayHello(name), 1000))
                .thenApply(response -> ok((String) response));
    }
}

注意すべき点はいくつかあります.
  • askモードを導入する必要があり、静的導入askは通常最も便利な方法である.
  • から戻るfutureCompletionStageに変換される.これによりpromiseはCompletionStage, , actor 。
  • askモードでtimeoutを とし、1000 millisecondsを した.actorがこの を える を やした . されるpromiseはtimeout errorになります.
  • このコンストラクタでactorを したため、Singletonとしてcontrollerを するたびに なactorを しないようにする があります.

  • Dependency injecting actors


    もしよろしければ、Guiceにactorsをインスタンス し、controllersとcomponents をバインドして することができます.
    たとえば、Play configurationに するactorが な は、 のようにします.
    import akka.actor.UntypedActor;
    import play.Configuration;
    
    import javax.inject.Inject;
    
    public class ConfiguredActor extends UntypedActor {
    
        private Configuration configuration;
    
        @Inject
        public ConfiguredActor(Configuration configuration) {
            this.configuration = configuration;
        }
    
        @Override
        public void onReceive(Object message) throws Exception {
            if (message instanceof ConfiguredActorProtocol.GetConfig) {
                sender().tell(configuration.getString("my.config"), self());
            }
        }
    }
    

    Playはacotr bindingsを するためにいくつかのhelpersを している. らはactor が に することを し、actorが が のコンポーネントに されることを することを する.バインディングactorは、これらのhelpersを して、dependency injection documentationインタフェースとAkkaGuiceSupportメソッドを してactorにバインディングするmodule bindActorを します.
    import com.google.inject.AbstractModule;
    import play.libs.akka.AkkaGuiceSupport;
    
    public class MyModule extends AbstractModule implements AkkaGuiceSupport {
        @Override
        protected void configure() {
            bindActor(ConfiguredActor.class, "configured-actor");
        }
    }
    

    actorは にconfigured-actorと され、configured-actorを いて される.コントロールラーや のcomponentsにactorに ることができます
    import akka.actor.ActorRef;
    import play.mvc.*;
    import scala.compat.java8.FutureConverters;
    
    import javax.inject.Inject;
    import javax.inject.Named;
    import java.util.concurrent.CompletionStage;
    
    import static akka.pattern.Patterns.ask;
    
    public class Application extends Controller {
    
        private ActorRef configuredActor;
    
        @Inject
        public Application(@Named("configured-actor") ActorRef configuredActor) {
           this.configuredActor = configuredActor;
        }
    
        public CompletionStage getConfig() {
            return FutureConverters.toJava(ask(configuredActor,
                            new ConfiguredActorProtocol.GetConfig(), 1000)
            ).thenApply(response -> ok((String) response));
        }
    }
    

    Dependency injecting child actors


    はroot actorsの についてですが、あなたが した くのactorはPlayアプリケーションのライフサイクルに られておらず、 のステータス がある があります.
    child actorsの を するため、PlayはGuiceのAssistedInjectによってサポートする.
    のactorがあるとします.configurationに して され、keyを します.
    import akka.actor.UntypedActor;
    import com.google.inject.assistedinject.Assisted;
    import play.Configuration;
    
    import javax.inject.Inject;
    
    public class ConfiguredChildActor extends UntypedActor {
    
        private final Configuration configuration;
        private final String key;
    
        @Inject
        public ConfiguredChildActor(Configuration configuration, @Assisted String key) {
            this.configuration = configuration;
            this.key = key;
        }
    
        @Override
        public void onReceive(Object message) throws Exception {
            if (message instanceof ConfiguredChildActorProtocol.GetConfig) {
                sender().tell(configuration.getString(key), self());
            }
        }
    }
    

    この ,コンストラクタ を い,Guiceの はコンストラクタ のみを することをサポートする.パラメータkeyは、 に され、コンテナを するのではなく、@Assisted を した.
    childプロトコルでは、Factoryインタフェースを します.
    import akka.actor.Actor;
    
    public class ConfiguredChildActorProtocol {
    
        public static class GetConfig {}
    
        public interface Factory {
            public Actor create(String key);
        }
    }
    

    たちはこのインタフェースを しません.Guiceは たちのためにこれらをして、 たちのkeyパラメータを するだけでなく、コンフィギュレーション を めして に する を します.Actorを すだけなので、このactorをテストすると、factorを して のactorを すことができます. えば、 のactorの わりに のchild actorを することができます.
    actor はInjectedActorSupportに され、 たちが したfactoryに することができます.
    import akka.actor.ActorRef;
    import akka.actor.UntypedActor;
    import play.libs.akka.InjectedActorSupport;
    
    import javax.inject.Inject;
    
    public class ParentActor extends UntypedActor implements InjectedActorSupport {
    
        private ConfiguredChildActorProtocol.Factory childFactory;
    
        @Inject
        public ParentActor(ConfiguredChildActorProtocol.Factory childFactory) {
            this.childFactory = childFactory;
        }
    
        @Override
        public void onReceive(Object message) throws Exception {
            if (message instanceof ParentActorProtocol.GetChild) {
                String key = ((ParentActorProtocol.GetChild) message).key;
                ActorRef child = injectedChild(() -> childFactory.create(key), key);
                sender().tell(child, self());
            }
        }
    }
    
    injectedChildを してchild actor を し、keyを して します.2 のパラメータはchild actorのnameとして されます.
    にはactorsをバインドする があります. たちのモジュールにあります.bindActorFactoryを してparent actorをバインドし、child factoryをchild にバインドします.
    import com.google.inject.AbstractModule;
    import play.libs.akka.AkkaGuiceSupport;
    
    public class MyModule extends AbstractModule implements AkkaGuiceSupport {
        @Override
        protected void configure() {
            bindActor(ParentActor.class, "parent-actor");
            bindActorFactory(ConfiguredChildActor.class,
                ConfiguredChildActorProtocol.Factory.class);
        }
    }
    

    Guiceが にバインドするインスタンス として された にコンフィギュレーションChildActorとして されるFactoryのインスタンス.

    Configuration


    デフォルトのactorシステム は、Playアプリケーションファイルから み みます.たとえば、デフォルトのアプリケーション・システムdispatcherを し、conf/application.confファイルに を します.
    akka.actor.default-dispatcher.fork-join-executor.pool-size-max = 64
    akka.actor.debug.receive = on
    

    Akkaのログ についてはconfiguring loggingを .

    Changing configuration prefix


    akka.*を いたいなら のAkka actor systemを すると、Playに の から の をロードするように えることができます.
    play.akka.config = "my-akka"
    

    akka の わりにmy-akka を み むように します.
    my-akka.actor.default-dispatcher.fork-join-executor.pool-size-max = 64
    my-akka.actor.debug.receive = on
    

    Built-in actor system name


    デフォルトのPlay actor systemのnameはapplicationです.conf/application.confを じて を えることができます
    play.akka.actor-system = "custom-name"
    

    Note: This feature is useful if you want to put your play application ActorSystem in an akka cluster.

    Executing a block of code asynchronously


    なAkkaの は であり, ・・・である.Actors poolを したのは、 を するためだけであることに づいたら、ここではもっと で い があります.
    import play.mvc.*;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.concurrent.CompletionStage;
    
    public class Application extends Controller {
        public CompletionStage index() {
            return CompletableFuture.supplyAsync(this::longComputation)
                    .thenApply((Integer i) -> ok("Got " + i));
        }
    }
    

    Scheduling asynchronous tasks


    にメッセージをactorに したり、タスクを したりすることができます.Cancellableが られ、cancelを び してタスクの をキャンセルすることができます.
    たとえば、testActor every 30 minutesにメッセージを できます.
    system.scheduler().schedule(
        Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay 0 milliseconds
        Duration.create(30, TimeUnit.MINUTES),     //Frequency 30 minutes
        testActor,
        "tick",
        system.dispatcher(),
        null
    );
    

    または、コードブロック10 millisecondsを ちに します.
    system.scheduler().scheduleOnce(
        Duration.create(10, TimeUnit.MILLISECONDS),
        () -> file.delete(),
        system.dispatcher()
    );