2017-09-25 7 views
0

J'écris un programme qui doit interagir avec une bibliothèque qui a été implémentée en utilisant Akka. En détail, cette bibliothèque expose un acteur en tant que point de terminaison. Pour autant que je sache et comme il est expliqué dans le livre Applied Akka Pattern, la meilleure façon d'interagir avec un système Actor de l'extérieur est d'utiliser Ask Pattern.Akka Ask Pattern avec de nombreux types de réponses

La bibliothèque que je dois utiliser expose un acteur Main qui accepte un message Create. En réponse à ce message, il peut répondre avec deux messages différents à l'appelant, CreateAck et CreateNack(error).

Le code que j'utilise est plus ou moins le suivant.

implicit val timeout = Timeout(5 seconds) 
def create() = (mainActor ? Create).mapTo[???] 

Le problème est clairement que je ne sais pas quel genre de type que je dois utiliser en fonction mapTo, au lieu de ???. Est-ce que j'utilise la bonne approche?

Existe-t-il un autre modèle utile pour accéder à un système d'acteur à partir d'un programme externe qui n'utilise pas Actors?

Répondre

2

En général, il est préférable de laisser les acteurs pour parler entre les acteurs, vous recevrez simplement une réponse alors - simple.

Si vous avez en effet à les intégrer avec le "outside", le motif ask est très bien. S'il vous plaît noter cependant que si vous faites cela à l'intérieur d'un acteur, ce n'est peut-être pas la meilleure façon de s'y prendre.

S'il y a un certain nombre de types de réponse sans rapport, je vous suggère:

(1) Faire ce type commun; cela peut être aussi simple que:

sealed trait CreationResponse 
final case object CreatedThing extends CreationResponse 
final case class FailedCreationOfThing(t: Throwable) extends CreationResponse 
final case class SomethingElse...(...) extends CreationResponse 

ce qui rend le protocole compréhensible, et traçable. Je recommande ceci car c'est explicite et aide à comprendre ce qui se passe.

(2) Pour les types complètement indépendants collecte simplement sur l'avenir travailleraient en passant, sans faire le mapTo:

val res: Future[...] = (bob ? CreateThing) collect { 
    case t: ThatWorked => t // or transform it 
    case nope: Nope => nope // or transform it to a different value 
} 

Cela fonctionnera de type bien sage si les résultats, t et nope ont une commune super type, ce type serait alors le ... dans le résultat Future. Si un message revient et ne correspond à aucun cas ce serait une erreur de correspondance; vous pourriez ajouter un case _ => whatever alors par exemple, OU cela pointerait vers une erreur de programmation.

+0

Merci beaucoup. Très belle et complète explication. En ce qui concerne votre phrase - ce qui rend le protocole compréhensible, et traçable, leur vrai programme utilise des noms compréhensibles :) –

0

Voir si CreateAck ou CreateNack(error) héritent de n'importe quel type de classe ou d'objet. Si c'est le cas, vous pouvez utiliser la classe parente ou l'objet dans le .mapTo[CreateResultType].

Une autre solution consiste à utiliser .mapTo[Any] et d'utiliser un match case pour trouver le type résultant.