2012-08-23 11 views
5

Tôi đang sử dụng akka một thời gian. Tôi bắt đầu thấy một số mẫu trong mã của tôi để giải quyết trả lời trễ cho async io. Việc triển khai này có ổn không? Có một cách khác để trả lời muộn mà không có khối?Trả lời trễ từ async io ở Akka

class ApplicationApi(asyncIo : ActorRef) extends Actor { 
    // store senders to late reply 
    val waiting = Map[request, ActorRef]() 

    def receive = { 
     // an actore request for a user, store it to late reply and ask for asyncIo actor to do the real job 
     case request : GetUser => 
      waiting += (sender -> request) 
      asyncIo ! AsyncGet("http://app/user/" + request.userId) 
     // asyncio response, parse and reply 
     case response : AsyncResponse => 
      val user = parseUser(response.body) 
      waiting.remove(response.request) match { 
       case Some(actor) => actor ! GetUserResponse(user) 
      } 
    } 
} 

Trả lời

5

Một cách để tránh chặn trong khi chờ trả lời được gửi bằng phương thức ask — a.k.a. Nhà điều hành ? — trả về số Future (không giống như ! trả về ()).

Sử dụng phương thức onSuccess hoặc foreach, bạn có thể chỉ định các hành động sẽ được thực hiện nếu/khi tương lai được hoàn thành với câu trả lời. Để sử dụng này, bạn cần phải trộn theo AskSupport đặc điểm:

class ApplicationApi(asyncIo : ActorRef) extends Actor with AskSupport { 

    def receive = { 
    case request: GetUser => 
     val replyTo = sender 
     asyncIo ? AsyncGet("http://app/user/" + request.userId) onSuccess { 
     case response: AsyncResponse => 
      val user = parseUser(response.body) 
      replyTo ! GetUserResponse(user) 
     } 

} 

Tránh sử dụng kỹ thuật này để thực hiện bất kỳ tác dụng phụ mà đổi trạng thái của diễn viên ApplicationApi, do hiệu ứng sẽ xảy ra out-of-sync với nhận vòng lặp. Chuyển tiếp tin nhắn cho các diễn viên khác nên được an toàn, mặc dù.


Bằng cách này, đây là một thủ thuật để nắm bắt hiện tại sender như một phần của mô hình phù hợp, tránh sự cần thiết để gán nó vào một biến sau đó.

trait FromSupport { this: Actor => 
    case object from { 
    def unapply(msg: Any) = Some(msg, sender) 
    } 
} 

class MyActor extends Actor with FromSupport { 
    def receive = { 
    case (request: GetUser) from sender => 
     // sender is now a variable (shadowing the method) that is safe to use in a closure 
    } 
} 
+1

Tôi nghĩ bạn là chính xác; Tôi quên rằng 'người gửi' là một tài sản có thể thay đổi của diễn viên và không chỉ là một biến có thể được đóng lại. –

+2

rằng bộ giải nén vô tận thực sự thú vị – sourcedelica