2013-06-09 33 views
7

Giả sử tôi có một số diễn viên lớp dịch vụ diễn viên khác thường được sử dụng. Ví dụ, một dịch vụ đăng ký lưu trữ và lấy đối tượng miền:Akka - Diễn viên dịch vụ thông thường: Xác định hoặc gia hạn

case class DomainObject(id: UUID) 

class Registry extends akka.actor.Actor { 
    def receive: Receive = { 
    case o: DomainObject => store(o) // save or update object 

    case id: UUID => sender ! retrieve(id) // retrieve object and send it back 
    } 
} 

Tôi không muốn để vượt qua một cách rõ ràng thể hiện của registry như vào tất cả các diễn viên có thể sử dụng nó. Thay vì nó, tôi muốn họ có thể bằng cách nào đó 'xác định' nó.

Đối với điều này tôi có thể nghĩ ra hai giải pháp:

  1. Identify thông điệp: mỗi diễn viên sử dụng registry biết tên diễn viên đăng ký từ một số cấu hình và có khả năng gửi tin nhắn xác định với nó. Sau AgentIdentity thông điệp được nhận lại chúng ta là tốt để đi:

    val registryName = ... // some name 
    val registryId = ... // some id 
    var registry = _ 
    
    def preStart() { 
        context.actorSelection(registryName) ! Identify(registryId) 
    } 
    
    def receive: Receive = { 
        case ActorIdentity(`registryId`, ref) => registry = ref 
    } 
    

    tôi không thích cách này bởi vì ngay sau khi sử dụng diễn viên khởi động có một giai đoạn khi chúng ta không biết nếu có một đăng ký trong hệ thống et tất cả và do đó không biết chúng ta sẽ có thể hoạt động hay không.

  2. Tiện ích mở rộng Akka: Tôi có thể tạo tiện ích mở rộng:

    a. tạo thể hiện của tác nhân Đăng ký trong Hệ thống diễn viên được bật khi khởi tạo;

    b. trả về tác nhân này cho người dùng cần nó thông qua một số phương pháp trong phần mở rộng.

    object RegistryKey extends ExtensionKey[RegistryExtension] 
    
    class RegistryExtesion(system: ExtendedActorSystem) extends RegistryKey { 
        val registry = system.actorOf(Props[Registry], "registry") 
    } 
    

Câu hỏi đặt ra là: phương pháp nào là tốt hơn và được Akka Extesions thể được sử dụng cho điều này ở tất cả?

+0

Tôi nghĩ bạn có nghĩa là 'context.actorSelection (registryName)! Xác định (registryId) '. 'actorFor' là một giải pháp khác mặc dù nó không được chấp nhận trong 2.2. – sourcedelica

+0

Vâng, bạn hoàn toàn chính xác. Rò rỉ bộ nhớ. :) – Seigert

Trả lời

3

Tôi nghĩ ý tưởng tiện ích mở rộng là một ý tưởng tốt miễn là diễn viên đăng ký của bạn luôn ở trong cùng một ActorSystem.

Ngoài ra, sử dụng actorSelection (chuyển thể từ Remote Lookup):

class RegistryClient extends Actor { 
    val path = "/path/to/registry/actor" 
    context.setReceiveTimeout(3.seconds) 

    def sendIdentifyRequest(): Unit = 
    context.actorSelection(path) ! Identify(path) 

    def receive = { 
    case ActorIdentity(`path`, Some(ref)) ⇒ 
     context.setReceiveTimeout(Duration.Undefined) 
     context.become(active(ref)) 
    case ActorIdentity(`path`, None) ⇒ 
     throw new RuntimeException("Registry not found") 
    case ReceiveTimeout ⇒ sendIdentifyRequest() 
    } 

    def active(registry: ActorRef): Actor.Receive = { 
    // use the registry 
    } 
} 

này sẽ làm việc cho các diễn viên từ xa hoặc địa phương.

Hãy xem giải pháp tiện ích. Actors are created asynchronously. Do đó, hàm tạo mở rộng của bạn sẽ không thành công khi gọi actorOf nếu tác nhân không khởi tạo được.

Nếu bạn muốn biết chắc chắn rằng diễn viên không khởi tạo được thì một cách để biết là ask tác nhân mà nó sẽ trả lời và Await một phản hồi. Await sẽ ném TimeoutException nếu tác nhân không trả lời.

class RegistryExtension(system: ExtendedActorSystem) extends Extension { 
    val registry = system.actorOf(Props[Registry], "registry") 
    implicit val timeout: Timeout = Timeout(500.millis) 
    val f = registry ? "ping" // Registry should case "ping" => "pong" 
    Await.result(f, 500.millis) // Will throw a TimeoutException if registry fails 
           // to respond 
} 

TimeoutException sẽ bị ném khi bạn gọi RegistryExtension(system).registry lần đầu tiên.

+0

Có, Registry luôn nằm trong cùng hệ thống với các diễn viên sử dụng nó. Mối quan tâm chính của tôi là cách Tiện ích hoạt động với khả năng chịu lỗi? Nếu bằng mọi cách, Tiện ích mở rộng sẽ không thể khởi tạo diễn viên đăng ký, điều đó có dẫn đến ngoại lệ diễn viên người dùng trong khi gọi phương thức Extension .registry không? Hoặc nó sẽ dẫn đến lỗi trên tiện ích mở rộng init? – Seigert

+0

câu trả lời được cập nhật để bao gồm việc tạo diễn viên đăng ký không thành công. – sourcedelica

+0

Tôi đã quyết định sử dụng cách tiếp cận hỗn hợp trong hệ thống: 'Xác định 'nơi cần có sự ghép nối hoặc từ xa thấp và Phần mở rộng cho các diễn viên có mặt trong hệ thống để nó hoạt động. – Seigert

3

Làm thế nào về Cake Pattern hoặc thư viện Dependency Injection chẳng hạn như subcut.

Derek Wyatt đề cập DI trong cuốn sách của ông 'Akka Concurrency' thay vì sử dụng quá nhiều actorFor để tìm kiếm diễn viên: http://www.artima.com/forums/flat.jsp?forum=289&thread=347118

+0

Vâng, tôi muốn giữ phụ thuộc dự án ở mức tối thiểu cho bây giờ. Vì vậy, tôi đoán, một lib khác chỉ dành cho DI của các diễn viên cho một diễn viên khác nằm ngoài giới hạn. – Seigert

+1

Mẫu Bánh không yêu cầu thêm phụ thuộc. Chỉ là Scala cốt lõi. – theon

+0

Đây là trường hợp điển hình mà Dependency Injection là công cụ chính xác. Bạn không cần phải làm gì nặng như import Spring và bắt đầu sử dụng XML khắp nơi, chỉ cần ref ref của diễn viên Registry là một tham số constructor cho tất cả các Actor phụ thuộc vào nó và theo đuổi những thay đổi đó. lúc khởi động ứng dụng và chuyển nó xung quanh toàn bộ ứng dụng. – Rich

Các vấn đề liên quan