2013-11-22 127 views
1

嗨akka gurus :)你能指導我這個嗎?Akka:等待多條消息

我正在試圖做的事 - 演員A向演員B詢問一條消息並等待一個人返回。但是,不知怎的,演員B不給A回覆一個消息,而是其中4個。演員A Future正確完成,但其餘3條消息計爲死信。爲什麼?這是正確的嗎?我的意思是,演員A有一個合適的處理者,爲什麼這些信件都死了呢? :-(

[INFO] [2013年11月22日22:00:38.975] [ForkJoinPool -2-工人-7] [阿卡://男演員/用戶/ A]而獲得的結果的乒乓[INFO ] [2013年11月22日 22:00:38.976] [演員-akka.actor.default-調度-4] [阿卡://男演員/ deadLetters]消息[java.lang.String中]從 演員[阿卡:// actors/user/b#-759739990]至 演員[akka:// actors/deadLetters]未投遞[1]遇到了死信 此日誌記錄可以關閉或通過 配置設置'akka進行調整。 log-dead-letters'和 'akka.log-dead-letters-during-shutdown'。 ...相同的消息2更多次...

請看看代碼。

package head_thrash 

import akka.actor._ 
import akka.util.Timeout 
import scala.concurrent.duration._ 
import akka.pattern.ask 
import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

object Main extends App { 
    val system = ActorSystem("actors") 

    val a = system.actorOf(Props[A], "a") 
    val b = system.actorOf(Props[B], "b") 

    a ! "ping" 
    system.awaitTermination() 
} 

class A extends Actor with ActorLogging { 

    implicit val timeout = Timeout(5.seconds) 

    def receive = { 
    case "ping" => { 
     val b = context.actorSelection("../b") 
     val future: Future[String] = ask(b, "ping").mapTo[String] 
     future.onSuccess { 
     case result: String ⇒ { 
      log.info("Got result " + result) // <-- got result pong here, that's okay 
     } 
     } 
    } 
    case "pong" => { 
     log.info("hmmm...") 
    } 
    } 
} 

class B extends Actor with ActorLogging { 
    def receive = { 
    case "ping" => { 
     sender ! "pong" 
     sender ! "pong" // <-- dead letter! 
     sender ! "pong" // <-- dead letter! 
     sender ! "pong" // <-- dead letter! 
    } 
    } 
} 

這真讓我困惑。現在你可以問 - 嘿,你爲什麼需要B發送很多消息?那麼,這是更復雜的案件的一部分 - A要求B的消息。 B回答。然後A 等待從B的另一個消息。這裏棘手的部分是明文未來完成後等待 - 我只是無法讓我的想法得到該模型適合阿卡基礎。

但現在,我怎樣才能得到正確處理所有4條消息,沒有死信?謝謝:-D

回答

3

你的問題是演員B沒有回答演員A.如果我們讀取documentation的問題模式,我們發現ask創建一個臨時的一次性演員接收消息的答覆,並完成一個scala.concurrent.Future與它。

這個臨時演員根本沒有處理"pong"消息,他只是在等待任何答案,然後您將投射爲未來的字符串。

如果要解決這個問題,必須修改你的演員B,使用第一它回答的臨時「問演員」,然後直接將消息發送給演員A.

class B extends Actor with ActorLogging { 
    def receive = { 
    case "ping" => { 
     sender ! "pong" //the sender is the temp ask actor 
     val a = context.actorSelection("../a") // get a ref on actor A 
     a ! "pong" 
     a ! "pong" 
     a ! "pong" 
    } 
    } 
} 

這是不是真的乾淨,但現在我希望你明白髮生了什麼。

+0

是的人。謝謝你,你是最棒的:) –

+1

你也可以在第一條消息中包含'sendAdditionaReplies:ActorRef'。 –

3

如果您不等待消息,您會發現代碼更容易編寫。當你不考慮你的應用程序的時間或步驟順序時,演員工作得最好。只要它能夠處理回調。但使用!不是?如果需要,可以使用FSM或FSM來顯示這兩種狀態。

這不是你問的問題,但它是你想知道的。避免使用演員的勢在必行的風格保持大多數這類錯誤的發生。

+0

嗯,我傾向於同意你的看法。詢問模式很難保持。 FSM研究,那麼:-D –

+1

是的,請問模式快得凌亂。我只會將它看作只針對特定邊緣情況的東西。就像在測試中你必須阻止響應一樣,以便測試正確運行。 這可能是因爲你不需要FSM。簡單的演員可以準備好處理其正常接收模塊中的回調。如果你需要它不做任何事情,直到它收到回調,然後使用FSM或成爲。變得更簡單,但FSM在需要時有更多附加組件。如轉換。 –