2011-06-03 6 views
6

タイムリーな結果を返すかもしれないし、返さないサービスを呼び出す必要があります。 Rubyのtimeoutのように - 私は仕事をする標準機能がありますタイムアウトのあるブロックを実行するための標準のScala関数はありますか?

val result = runWithTimeout(5000, valReturnedOnTimeout) { service.fetch } 

書くことができるようにしたいのですが?

+0

はい、私は俳優を使ってこれを解決することは知っていますが、このような単純な問題のために残忍なようです。 –

+0

関連するhttp://stackoverflow.com/q/5797666/132374 –

答えて

6

- 中標準ライブラリ関数がないので、私はFuturesルートをダウンしました。

import scala.concurrent._ 
    import scala.concurrent.duration._ 

    def runWithTimeout[T](timeoutMs: Long)(f: => T) : Option[T] = { 
    Await.result(Future(f), timeMins milliseconds).asInstanceOf[Option[T]] 
    } 

    def runWithTimeout[T](timeoutMs: Long, default: T)(f: => T) : T = { 
    runWithTimeout(timeoutMs)(f).getOrElse(default) 
    } 

だから

@Test def test { 
    runWithTimeout(50) { "result" } should equal (Some("result")) 
    runWithTimeout(50) { Thread.sleep(100); "result" } should equal (None) 
    runWithTimeout(50, "no result") { "result" } should equal ("result") 
    runWithTimeout(50, "no result") { Thread.sleep(100); "result" } should equal("no result") 
    } 

私はこれは良いScalaのスタイルであるかどうかについてどのようなフィードバックに感謝するだろう!

+0

私はこれを例外に対処するために拡張しました。http://stackoverflow.com/questions/6229778 –

1

新しいスレッドで開始し、それがThread.joinで終了するのを待つことができます。結合するためにパラメータを渡すと、そのパラメータは最大でも数ミリ秒待機します。

val t = new Thread { 
    override def run() { 
    //... 
    } 
} 
t.start() 
t.join(5000) 
+0

ありがとう、私はExecutorsフレームワークを使用することもできます。しかし、私は何か組み込みや慣用的なものを見逃していないことを確認していました。 –

2

マイトFuturesとそのalarmは、トリックを行いますか?

+0

私はそれを見たことがありませんでした、ありがとう、それは確かに機能を実装する方法です - それがまだ存在しない場合。 –

5

あなたが将来

import scala.actors.Futures._ 

val myfuture = 
    future { 
    Thread.sleep(5000) 
    println("<future>") 
    "future " 
} 

awaitAll(300,myfuture) foreach println _ 

使用ししかし、また Circuit Breaker Patternの実装ですCircuit Breaker for Scalaを見ている可能性があります。基本的にそれはあなたがタイムアウトを制御し、障害が(READMEから)

使い方はScalaで次のようになり、外部リソースへのアクセスが発生した場合、何が起こるべきことができます:

他の回答に信用して
. . . 
addCircuitBreaker("test", CircuitBreakerConfiguration(timeout=100,failureThreshold=10)) 
. . . 


class Test extends UsingCircuitBreaker { 
    def myMethodWorkingFine = { 
    withCircuitBreaker("test") { 
     . . . 
    } 
    } 

    def myMethodDoingWrong = { 
    withCircuitBreaker("test") { 
     require(false,"FUBAR!!!") 
    } 
    } 
} 
+0

私はサーキットブレーカが好きですが、標準ライブラリには何もないと思います。私はFuturesに基づいて何かを書いてみて、それを簡単に保つつもりです。 –

+0

将来はスレッドをブロックすることに注意してください。 http://stackoverflow.com/q/5646879/203968あなたを何度も呼び出すクライアントがあなたのスレッドを飢えさせるかもしれません。したがって回路遮断器。呼び出しがおそらくうまくいかないと思うときに "回線を壊す"可能性があります。 – oluies

+0

はい、私はそれを考慮する必要があります。呼び出しがWebレイヤーにあるので、ブラウザごとに1つずつ持つことができます。私はブラウザをポーリングし、最後にExecutorsを使用しなければならないかもしれません。 –

2

まだ言及されていないものは、awaitEitherです。これは、アクターパッケージのFuturesオブジェクトのメソッドです。次いで

awaitEither(future{task}, alarm(timeoutPeriod)) 

と示唆されたように方法に着飾っ:

def runWithTimeout[T](timeoutPeriod: Int, timeoutValue: T)(task: => T) = { 
    awaitEither(future{task}, alarm(timeoutPeriod)) match {case() => timeoutValue case x => x} 
} 

このような例示的なものを使用することができるために、完了することが先物の対の最初から結果を返すawaitEither alarm戻り値の型に割り当てることができるUnitしたがって、awaitEitherはパターンマッチングできるものを返します。

+0

@ pr1001が「アラーム」を指摘したが、おそらくアラームのために別のスレッドを開始すると思った。少し過度のように見えた。それは素敵な短い表現のために作る。 –