2011-06-03 14 views
6

Necesito llamar a un servicio que puede o no devolver resultados oportunos. Me gustaría ser capaz de escribir¿Hay una función estándar de Scala para ejecutar un bloque con un tiempo de espera?

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

¿Hay una función estándar que hará el trabajo - como Ruby de timeout?

+0

Y sí, sé que usar Actors resolvería esto, pero parece demasiado para un problema tan simple. –

+0

Relacionados con http://stackoverflow.com/q/5797666/132374 –

Respuesta

6

Con el crédito a las otras respuestas - en la ausencia de cualquier función de biblioteca estándar, he seguido la ruta 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) 
    } 

Para que

@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") 
    } 

Estaría agradecido por cualquier información sobre si este es un buen estilo Scala!

+0

He extendido esto para tratar con excepciones en http://stackoverflow.com/questions/6229778 –

1

Puede iniciarlo en un nuevo subproceso y esperar a que termine con Thread.join. Si pasa un parámetro para unirse, espera como máximo esos milisegundos.

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

Gracias, y también podría usar el marco de los ejecutores. Pero estaba comprobando que no me estaba perdiendo algo incorporado o idiomático. –

2

Poder Futures y su alarm hacer el truco?

+0

No había visto eso, gracias, y ciertamente es una forma de implementar la función, si es que aún no existe. –

5

Se puede usar un futuro

import scala.actors.Futures._ 

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

awaitAll(300,myfuture) foreach println _ 

Pero también echar un vistazo a Circuit Breaker for Scala que es una aplicación de la Circuit Breaker Pattern. Básicamente se le permite controlar el tiempo de espera y lo que debe suceder si se produce un fallo para acceder a un recurso externo

uso es la siguiente con Scala (desde el readme):

. . . 
addCircuitBreaker("test", CircuitBreakerConfiguration(timeout=100,failureThreshold=10)) 
. . . 


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

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

Me gustan los interruptores automáticos, pero supongo que no hay nada en la biblioteca estándar. Trataré de escribir algo basado en Futures para hacerlo simple. –

+0

tenga en cuenta que el futuro bloquea el hilo. http://stackoverflow.com/q/5646879/203968 Así que un cliente que lo llama muchas veces puede terminar muriendo de hambre. De ahí el interruptor de circuito.donde podría "romper el circuito" cuando crea que la llamada probablemente no funcione – oluies

+0

Sí, voy a tener que considerar eso, ya que las llamadas están en mi capa web y puedo tener una por navegador. Es posible que deba tener la encuesta del navegador y usar ejecutores al final. –

2

Algo que no se ha mencionado aún es awaitEither, un método en el objeto Futures del paquete de actores. awaitEither devuelve el resultado de la primera de un par de futuros para completar, así que por ejemplo algo como esto podría ser utilizado:

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

y luego vestido con un método como se sugiere:

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

alarma devuelve unidad que se puede asignar a un val de tipo Cualquiera que esté tan esperado. Devuelve algo que puede coincidir con un patrón.

+0

Consideré que cuando @ pr1001 señaló 'alarma' pero pensé que probablemente terminaríamos iniciando otro hilo de alarma, que parecía un poco exagerado Sin embargo, es una bonita expresión corta. –

Cuestiones relacionadas