web-dev-qa-db-ja.com

Akkaアクター(akka 2.2)が存在するかどうかを確認するにはどうすればよいですか?

私はJavaオブジェクトであり、これはactorSelection(Path)でアクターシステムからアクターを選択するアクターではありません)を持っています。選択した俳優がシステムに存在しない可能性があります。

Javaには、ActorSelectionのApi ask()が存在しないため、Actor選択に送信および識別メッセージを送信できず、応答の送信者を使用できません。

アクターの選択を介してとにかくメッセージをアクターに送信し、その後デッドレターに反応することで問題を解決しようとしました。しかし、私はどんなデッドレターも受け取りません。

アクターが生きているか存在しないかをActorSelectionで確認するにはどうすればよいですか?

ActorSystem system = ActorSystem.create("test");

//create test actor
system.actorOf(Props.create(TestActor.class), "testActor");

//add dead letter listener to the system
ActorRef eventBusActor = asys.actorOf(Props.create(EventBusActor.class), "eventbusactor");
system.eventStream().subscribe(eventBusActor, DeadLetter.class);


//This works. The test actor receives the message      
ActorSelection a1 = asys.actorSelection("/user/testActor");
a1.tell("hello", ActorRef.noSender());

//This does not work and does not send dead letters      
ActorSelection a2 = asys.actorSelection("/user/doesnotexist");
a2.tell("hello", ActorRef.noSender());

//Does not compile, because ask needs an ActorRef as first argument
ActorSelection a3 = asys.actorSelection("/user/test");
Future f = Patterns.ask(a3, new Identify(), 1000);
21
schrums

Java api for ActorSelection)でAkkaがaskのサポートを中止したようです。コードを少し遊んでみましたが、動作するものが見つかりました。このコードが機能するかどうかを確認してください:

import Java.util.concurrent.TimeUnit;

import scala.concurrent.Await;
import scala.concurrent.Future;

import akka.actor.ActorIdentity;
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.ActorSystem;
import akka.actor.Identify;
import akka.actor.Props;
import akka.pattern.AskableActorSelection;
import akka.util.Timeout;

public class AskTest {

  public static void main(String[] args) throws Exception{
    ActorSystem sys = ActorSystem.apply("test");
    sys.actorOf(Props.create(TestActor.class), "mytest");

    ActorSelection sel = sys.actorSelection("/user/mytest");

    Timeout t = new Timeout(5, TimeUnit.SECONDS);
    AskableActorSelection asker = new AskableActorSelection(sel);
    Future<Object> fut = asker.ask(new Identify(1), t);
    ActorIdentity ident = (ActorIdentity)Await.result(fut, t.duration());
    ActorRef ref = ident.getRef();
    System.out.println(ref == null);
  }
}

scala Ask supportがどのように機能し、Javaを介してそれにフックされているかを確認しました。これは私にとってはうまくいきました。あなたにとってそれがうまくいくことを願っています。

13
cmbaxter

私は最近ActorSelection.resolveOneメソッドを見つけました:

val name = "myActor"
implicit val timeout = 5000 // Timeout for the resolveOne call
system.actorSelection(name).resolveOne().onComplete {
  case Success(actor) => actor ! message

  case Failure(ex) =>
    val actor = system.actorOf(Props(classOf[ActorClass]), name)
    actor ! message
}

私がまだ調査している1つの問題は、これが定義されているメソッドが(他のアクターから)同時に呼び出される可能性があることです。したがって、アクターがまだ作成されているためresolveOne呼び出しが失敗した場合に、アクターを2回作成しようとする競合状態が発生する可能性があります。これは、ユースケースの問題である場合とそうでない場合があります

25
Mario Camou

Akkaは、特別なメッセージActorRefを使用してActorSelectionからIdentifyを取得する機能を提供します。このメッセージにask()を使用する必要はありません。特定メッセージをActorSelectionに渡して、返されるActorIdentityメッセージをリッスンするだけです。これの正確な例は、Akkaのドキュメントにあります。 Actor Selection(Java)を使用して俳優を識別する

このコードは例から取得され、変更されています。

final String identifyId = "1";

@Override
public void onReceive(Object message) {
    if (message instanceof ActorIdentity) {
        ActorIdentity identity = (ActorIdentity) message; 
        if (identity.correlationId().equals(identifyId)) {
            ActorRef ref = identity.getRef();
            if (ref == null)
                // Actor does not exist
            else {
                // Actor does exist
            }
        }
     }
}

ドキュメントには、ActorPath、ActorSelection、Actorライフサイクルの関係を示す、とても素晴らしい graphic もあります。

6
Björn Jacobs

他の回答が注記しているように、ActorSelection.resolveOne()がこれを処理します。

1つの警告:内部的には、これは問題の俳優にメッセージを送信することで機能します。つまり、そのアクターがビジー状態の場合は応答せず、これは失敗します(タイムアウト付き)。

純粋なベストプラクティスアッカでは、これはたぶんコーナーケースです。より混合された通常のJava/Akkaの設定では、むちゃくちゃになるのは簡単です。特に、アクターのスレッド内のコードは、そのアクターへの参照を見つけることができません。

4

バージョン2.3.4の使用

いくつかのScalaの例、おそらく助けることができます

  val zed2 = Akka.system().actorSelection("path")
  val fs:FiniteDuration = (100).millis

  val x = zed2.resolveOne(fs).value
  if (x.isDefined){
    println(x.get.isFailure)
  }
1
Ivan Gonzalez