2013-11-09 38 views
3

裏面我有一個功能重試基本上看起來像這樣(簡化):調用了Thread.sleep演員

object SomeObject { 
def retry[T](n: Int)(fn: => T): Option[T] = { 
    val res = try { 
     Some(fn) 
    } catch { 
     case _: Exception => None 
    } 

    res match { 
     case Some(x) => Some(x) 
     case None => 
     if (n > 1) 
      //make it sleep for a little while 
      retry(n - 1)(fn) 
     else None 
    } 
    } 
} 

我需要做的嘗試之間的一些暫停。據我所知,這是不能接受的調用Thread.sleep(123)演員裏面:

class MyActor extends Actor { 
    //...... 
    def someFunc = { 
    Thread.sleep(456) // it's not acceptable in an actor, there is another way to do it 
    } 

} 

很顯然,我不知道客戶是否會使用SomeObject.retry演員裏面:

class MyActor extends Actor { 
    //...... 
    def someFunc = { 
    SomeObject.retry(5)(someRequestToServer) // ops, SomeObject.retry uses Thread.sleep! 
    } 

} 

所以,如果我只是補充:

res match { 
     case Some(x) => Some(x) 
     case None => 
     if (n > 1) 
      //make it sleep for a little while 
      Thread.sleep(123) // ops, what if it's being called inside an actor by a client?! 
      retry(n - 1)(fn) 
     else None 
    } 
    } 

它不會是明智的,會嗎?如果不是,我該怎麼辦?

回答

5

是的,調用Thread.sleep是一個壞主意,因爲在actor系統中線程通常是Actors之間共享的有限資源。你不希望一個Actor調用sleep並且從其他Actor中竊取一個Thread。

您應該做的是使用Scheduler(請參閱docs)讓您的演員在將來某個時間向其自身發送消息以重試。要做到這一點,你會如果你使用SomeObject.try外的演員來移動重試碼出SomeObject進入Actor

class MyActor extends Actor { 

    import context.system.dispatcher 

    def receive = { 
    case DoIt(retries) if retries > 0 => 
     SomeObject.attempt(someRequestToServer) match { 
     case Some(x) => ... 
     case None => 
      context.system.scheduler.scheduleOnce(5.seconds, self, DoIt(retries - 1)) 
     } 
    } 

} 

然後系統

def attempt(retries: Int) = { 
    SomeObject.attempt(someRequestToServer) match { 
    case Some(x) => ... 
    case None if retries > 0 => { 
     Thread.sleep(123) 
     attempt(retries - 1) 
    } 
    } 
} 

其中SomeObject.attempt是:

object SomeObject { 
    def attempt[T](fn: => T): Option[T] = 
    try { 
     Some(fn) 
    } catch { 
     case _: Exception => None 
    } 
} 
+0

如果您將'SomeObject.attempt'中的所有代碼移出它,那麼SomeObject.attempt'方法中剩下的代碼是什麼? –

+0

不是很多。在'attempt'中留下的所有內容都將是'retry'方法中的'try'' catch',它會返回'None'或'Some'。因爲在一個Actor系統中等待/重試的代碼與在純多線程系統中等待/重試的代碼有很大不同,所以很難從兩者中獲得任何可重用的公共代碼。 – theon

+0

可以請你展示完整的例子嗎?我找不到應該在1)SomeObject.attempt 2)def嘗試(...)case Some(x)=> ... –