2017-10-15 4 views
0

Pour une raison quelconque, je dois utiliser gRPC et Akka en même temps. Quand cet acteur est démarré comme un acteur de premier plan, rien ne va mal (dans cette petite démo). Mais quand il devient un enfant acteur, il ne peut pas recevoir de messages, et le suivant est enregistré:ExecutionContext provoque Akka lettre morte

[default-akka.actor.default-dispatcher-6] [akka://default/user/Grpc] Message [AkkaMessage.package$GlobalStart] from Actor[akka://default/user/TrackerCore#-808631363] to Actor[akka://default/user/Grpc#-1834173068] was not delivered. [1] dead letters encountered. 

L'exemple principal:

class GrpcActor() extends Actor { 
    val ec = scala.concurrent.ExecutionContext.global 
    val service = grpcService.bindService(new GrpcServerImpl(), ec) 
    override def receive: Receive = { 
     case GlobalStart() => { 
      println("GlobalStart") 
     } 
     ... 
    } 
} 

J'ai essayé de créer une nouvelle ExecutionContext comme:

scala.concurrent.ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10)) 

Pourquoi cela se produit-il, et comment puis-je déboguer un problème de lettres mortes comme celui-ci (aucune exception n'est levée)?

Mise à jour:

Désolé, je ne l'ai pas énumérer tout ici. J'ai utilisé la méthode Main normale pour tester GrpcActor en tant qu'acteur principal, et ScalaTest pour le tester en tant qu'acteur enfant, ce qui est une erreur.

class GrpcActorTest extends FlatSpec with Matchers{ 
    implicit val system = ActorSystem() 
    val actor: ActorRef = system.actorOf(Props[GrpcActor]) 
    actor ! GlobalStart() 
} 

C'est cette suite de tests vide qui active le système d'acteur entier. Mais le problème est avec cette ligne

val service = grpcService.bindService(new GrpcServerImpl(), ec) 

la livraison de GlobalStart() a été retardée après l'arrêt.

Sans cette ligne, un message peut être délivré avant l'arrêt.

Est-ce un comportement normal?

(Je pense: il est arrivé que la GlobalStart() était mise en file après le message d'arrêt avec cette ligne, ce qui a fait un travail lourd et a fait la différence dans le temps)

+0

Merci @chunjef pour avoir corrigé mes fautes de grammaire et avoir perfectionné cette question. – Skye347

Répondre

0

Une façon de résoudre le problème est de faire une servicelazy val:

class GrpcActor extends Actor { 
    ... 
    lazy val service = grpcService.bindService(new GrpcServerImpl(), ec) 
    ... 
} 

Un lazy val est utile pour les opérations de longue durée: en dans ce cas, il reporte l'initialisation de service jusqu'à son utilisation initiale. Sans le modificateur lazy, service est initialisé lorsque l'acteur est créé.

Une autre approche consiste à ajouter un Thread.sleep dans votre test pour empêcher le système d'acteur de se fermer avant que l'acteur a complètement initialisé:

class GrpcActorTest extends FlatSpec with Matchers { 
    ... 
    actor ! GlobalStart() 
    Thread.sleep(5000) // or whatever length of time is needed to initialize the actor 
} 

(Comme une note de côté, pensez à utiliser Akka Testkit pour votre tests d'acteur.)

0

Ajouter une stratégie de superviseur à son parent, ajouter println à le cycle de vie de l'acteur. Il y a quelque chose qui tue ton acteur. Enfin, si vous fournissez un exemple complet peut-être que je peux dire plus :)