각 Actor들은 고유한 논리적인 경로를 가지고 있다. 이러한 논리적 경로는 자식 액터부터 부모 액터로 타고 올라가 최후에는 액터 시스템의 루트, 즉 액터 시스템의 최상위까지 갈 수 있다.
이러한 경로들은 액터들을 찾기위해 사용된다. 예를 들어 메시지 수신자를 찾을 때, 직접적으로 갈 수 있는 경로를 찾는 것이다.
Actor들은 다른 액터들과의 상대 경로나 절대 경로를 통해 구분된다. 즉, 논리적 혹은 물리적 경로를 통해 구분된다. 그리고, 이 결과는 ActorSelection
에서 결과를 가져올 수 있다.
대부분의 경우, ActorRef
를 통해 다른 액터와 커뮤니케이션을 하는 것이 선호되지만, 다음과 같은 예외가 있다.
1. at least once delivery
를 사용하며 메시지를 보낼 때
2. remote system과 최초로 컨택 후 초기화할 때
at least once delivery
at-least-once delivery는 분산 데이터 파이프라인에서 데이터 전달 보장 방법 중 하나이다.
at-least-once delivery는 최소한 한 번 메시지 전송 보장으로 sender가 메시지를 전송하고 일정 시간 내에 receiver에게 ACK를 받지 못했다면 다시 메시지를 전송하는 방식이다.
Receiver가 메시지를 받았다는 ACK 패킷을 확인할 때까지 계속 메시지를 전송하므로 최소한 한 번의 메시지 전송을 보장한다.
이 방법은 중복 메시지 발생 가능성이 높으므로 중복 메시지가 있어도 되는 경우 사용한다.
// will look up this absolute path
context.actorSelection("/user/serviceA/aggregator")
// will look up sibling beneath same supervisor
context.actorSelection("../joe")
코드에서는 위와 같이 context.actorSelection(상대 혹은 절대 경로)
형태로 코드를 작성한다. 이때, 안에 들어갈 경로들은 java.net.URI
로 파싱된다. 즉, /
단위로 경로 원소들을 나누는 것이다. /
로 시작한다면 루트로 시작한다고 생각한다. 그것이 아니라면, 현재 액터로부터 시작하는 경로로 생각한다.
// serviceB 디렉터리 내의 worker로 시작하는 모든 자손들을 확인
context.actorSelection("/user/serviceB/worker*")
context.actorSelection("../*")
위와 같이 *
을 사용하여 와일드카드를 나타낼 수도 있다.
위와 같이 ActorSelection
의 내부에 있는 경로를 통해 메시지들이 전송될 것이다. 그리고, 해당 메시지에 답신을 보내기 위해서는 sender
라는 메서드를 사용할 것이다.
sender()
메시지의 발신자를 리턴한다.
이때, 모든 액터들이 이해하고 자동적으로 ActorRef
를 담고 있는 ActorIdentity
로 답신하는 빌트인 Identify
메시지가 있다. 이 매시지는 구체적인 이름 찾기가 실패할 경우 순회하여 답을 찾아낸다.
import akka.actor.{ Actor, ActorIdentity, Identify, Props, Terminated }
class Follower extends Actor {
val identifyId = 1
context.actorSelection("/user/another") ! Identify(identifyId)
def receive = {
case ActorIdentity(`identifyId`, Some(ref)) =>
context.watch(ref)
context.become(active(ref))
case ActorIdentity(`identifyId`, None) => context.stop(self)
}
def active(another: ActorRef): Actor.Receive = {
case Terminated(`another`) => context.stop(self)
}
}
위의 코드는 /user/another
라는 경로에서 액터를 찾아 Identify(1)을 보내고, 응답을 받았을 때 해당 ref에 active 메서드를 적용시키는 코드이다.
이때 유의할 점은 응답이 보장되는 것은 아니다라는 사실이다.