[英]Scala actor: receiveWithin() doesn't receive messages
我正在Scala中構建一個基於actor的服務,消費者可以在其中查詢客戶端是否已獲得授權,還可以授權客戶端。
如果消費者查詢客戶端的授權狀態並且該客戶端尚未被授權,則該actor應該在指定的超時內等待傳入的Authorize
消息,然后發送回復。 IsAuthorized
應該能夠在消費者代碼中同步執行,以便阻止並等待回復。 就像是
service !? IsAuthorized(client) => {
case IsAuthorizedResponse(_, authorized) => // do something
}
但是我的actor中的receiveWithin()
從不接收消息並且總是進入超時。
這是我的代碼
case object WaitingForAuthorization
case class WaitingForAuthorizationResponse(clients: immutable.Set[Client])
case class IsAuthorized(client: Client)
case class IsAuthorizedResponse(client: Client, authorized: Boolean)
case class Authorize(client: Client)
class ClientAuthorizationService {
private val authorized: mutable.Set[Client] = new mutable.HashSet[Client] with mutable.SynchronizedSet[Client]
private val waiting: mutable.Set[Client] = new mutable.HashSet[Client] with mutable.SynchronizedSet[Client]
def actor = Actor.actor {
loop {
react {
case IsAuthorized(client: Client) => reply {
if (authorized contains client) {
IsAuthorizedResponse(client, true)
} else {
waiting += client
var matched = false;
val end = Instant.now.plus(ClientAuthorizationService.AUTH_TIMEOUT)
while (!matched && Instant.now.isBefore(end)) {
// ERROR HERE: Never receives Authorize messages
receiveWithin(ClientAuthorizationService.AUTH_TIMEOUT) {
case Authorize(authorizedClient: Client) => {
authorizeClient(authorizedClient)
if (authorizedClient == client) matched = true
}
case TIMEOUT => // do nothing since we handle the timeout in the while loop
}
}
IsAuthorizedResponse(client, matched)
}
}
case Authorize(client: Client) => authorizeClient(client)
case WaitingForAuthorization => reply {
WaitingForAuthorizationResponse(immutable.Set() ++ waiting)
}
}
}
}
private def authorizeClient(client: Client) = synchronized {
authorized += client
waiting -= client
}
}
object ClientAuthorizationService {
val AUTH_TIMEOUT: Long = 60 * 1000;
}
當我在發送者在receiveWithin塊中發送Authorize
消息時,消息被下面的第二個case語句捕獲,實際上只有在當時沒有人等待響應時才捕獲這些消息。
我的代碼出了什么問題?
更新:
這是相關代碼的縮短版本,它實際上代表了一個更簡單和不同的邏輯,但可能更好地澄清了問題:
loop {
react {
case IsAuthorized(client: Client) => reply {
var matched = false
// In the "real" logic we would actually loop here until either the
// authorized client matches the requested client or the timeout is hit.
// For the sake of the demo we only take the first Authorize message.
receiveWithin(60*1000) {
// Although Authorize is send to actor it's never caught here
case Authorize(authorizedClient: Client) => matched = authorizedClient == client
case TIMEOUT =>
}
IsAuthorizedResponse(client, matched)
}
case Authorize(client: Client) => // this case is hit
}
}
更新2:
我終於解決了這個問題。 我認為問題在於演員在嘗試在回復前面的IsAuthorized
消息時收到Authorize
消息時阻止了。
我重寫了代碼,以便在我們等待Authorized
時啟動匿名Actor。 這是感興趣的人的代碼。 waiting
是Map[Client, Actor]
。
loop {
react {
case IsAuthorized(client: Client) =>
if (authorized contains client) {
sender ! IsAuthorizedResponse(client, true)
} else {
val receipient = sender
// Start an anonymous actor that waits for an Authorize message
// within a given timeout and sends a reply to the consumer.
// The actor will be notified by the parent actor below.
waiting += client -> Actor.actor {
val cleanup = () => {
waiting -= client
exit()
}
receiveWithin(ClientAuthorizationService.AUTH_TIMEOUT) {
case Authorize(c) =>
receipient ! IsAuthorizedResponse(client, true)
cleanup()
case TIMEOUT =>
receipient ! IsAuthorizedResponse(client, false)
cleanup()
}
}
}
case Authorize(client: Client) =>
authorized += client
waiting.get(client) match {
case Some(actor) => actor ! Authorize(client)
case None =>
}
case WaitingForAuthorization => sender ! WaitingForAuthorizationResponse(immutable.Set() ++ waiting.keySet)
}
}
如果有更好的方法來解決這個問題,請告訴我!
是不是回復了問題? 在
case IsAuthorized(client: Client) => reply { ... }
所有代碼都在回復塊的參數中,因此在實際發送回復之前執行它(包括receiveWithing)。 這意味着當您的客戶處理您的回復時,您將不再等待它。
在您的原始代碼中,它應該是類似的東西
case IsAuthorized(client: Client) =>
if(ok) reply(AuthorizedReply(client, true))
else {
reply(AuthorizedReply(client, false))
receiveWithin(...)
}
我終於解決了這個問題。 我認為問題在於演員在嘗試在回復前面的IsAuthorized
消息時收到Authorize
消息時阻止了。
我重寫了代碼,以便在我們等待Authorized
時啟動匿名Actor。 這是感興趣的人的代碼。 waiting
是Map[Client, Actor]
。
loop {
react {
case IsAuthorized(client: Client) =>
if (authorized contains client) {
sender ! IsAuthorizedResponse(client, true)
} else {
val receipient = sender
// Start an anonymous actor that waits for an Authorize message
// within a given timeout and sends a reply to the consumer.
// The actor will be notified by the parent actor below.
waiting += client -> Actor.actor {
val cleanup = () => {
waiting -= client
exit()
}
receiveWithin(ClientAuthorizationService.AUTH_TIMEOUT) {
case Authorize(c) =>
receipient ! IsAuthorizedResponse(client, true)
cleanup()
case TIMEOUT =>
receipient ! IsAuthorizedResponse(client, false)
cleanup()
}
}
}
case Authorize(client: Client) =>
authorized += client
waiting.get(client) match {
case Some(actor) => actor ! Authorize(client)
case None =>
}
case WaitingForAuthorization => sender ! WaitingForAuthorizationResponse(immutable.Set() ++ waiting.keySet)
}
}
如果有更好的方法來解決這個問題,請告訴我!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.