如何多次重复等待?
How to repeat Await multiple times?
我是 Scala 的新手。
我只想在超时时重试 code1
。如果再出现错误,我会换种方式处理。如果超时,我想再试一次,比如3次。这样做的正确方法是什么?
我不确定使用 code2
之类的东西是否是在 Scala 上执行此操作的最佳方式。也许已经有更好的东西了。有没有更清洁的破解方法?我应该使用 Await.ready 而不是结果吗?
我也不确定我是否应该使用 Await.ready 或 Await.result。
代码 1:
Await.result(myMethod(), Duration(120, "seconds"))
代码 2:
breakable {
for(_ <- 0 to 3) {
Try(Await.result(myMethod(), Duration(120, "seconds"))) match {
case Success(value) => {
// do something
break()
}
case Failure(_) => // how can I now if it is timeout?
}
}
}
您可以使用递归来实现简单的重试机制。匹配 TimeoutException
失败将使您能够专门处理超时情况。
下面是一个例子,假设 myMethod
returns 一个 Future[String]:
def myMethod(): Future[String] = ???
val maxAttempts = 3
def retryOnTimeout(attempt: Int = 0): String = {
Try(Await.result(myMethod(), Duration(120, "seconds"))) match {
case Success(result) => result
case Failure(_: TimeoutException) if attempt < maxAttempts => retryOnTimeout(attempt + 1)
case Failure(err) => throw err
}
}
retryOnTimeout
可以变得更通用,允许它在多个地方使用,函数作为参数传入。
等待 Future
会使整个 Future
变得毫无意义。也就是说,应该处理 3 种情况:
- 所有尝试都超时
- 一个non-time-out失败
- a
Future
成功完成
import scala.concurrent.duration._
import scala.concurrent.{Future, Await, TimeoutException}
import scala.util.{Try, Success, Failure}
// v--max number of attempts
LazyList.fill(4)(Try(Await.result(myMethod(), 120.seconds)))
.dropWhile{case Failure(_:TimeoutException) => true
case _ => false
}.headOption.fold{
//every attempt timed out
}{
case Success(value) => //do something
case Failure(ex:Throwable) => //ex is non-timeout exception
}
注意:LazyList
是 Scala 2.13.x 集合。列表中的每个元素只被评估 if/when 它是必需的,所以如果第一个成功,那么 none 其他期货将被启动。
您可以尝试将以下方法应用于 repeating evaluation
。
下面的代码片段定义了一个通用的 retry
方法:这个方法接受一个参数,在 try - catch
块中对其进行计算,并且 re-executes 它在失败时最大数量尝试。
让 retry
接受 by-name parameter
是允许它在必要时重复计算 myMethod block
的原因。
object Test {
def retry[T](max: Int)(f: => T): T = {
var tries = 0
var result: Option[T] = None
while (result == None) {
try {
result = Some(f)
}
catch {
case e: Throwable => tries += 1
if (tries > max) throw e
else {
println(s"failed, retry #$tries")
}
}
}
result.get
}
def myMethod(n: Int): Int = {
val num = scala.util.Random.nextInt(10)
if(n < num) throw new Exception
else num
}
def main(args: Array[String]): Unit = {
println(retry(max = 5){myMethod(3)})
/*
failed, retry #1
failed, retry #2
3
*/
println(retry(max = 5){myMethod(-1)})
/*
failed, retry #1
failed, retry #2
failed, retry #3
failed, retry #4
failed, retry #5
Exception in thread "main" java.lang.Exception
*/
}
}
注意
myMethod
函数可以采用新的参数超时来为每个函数调用引入一些时间限制。
def myMethod(n: Int, timeout: Long): Int = {
var num = scala.util.Random.nextInt(10)
val current = System.currentTimeMillis()
var running = System.currentTimeMillis()
while (running - current <= timeout && n < num) {
num = scala.util.Random.nextInt(10)
running = System.currentTimeMillis()
}
println(s"time goes on ${running - current}")
if(n < num) throw new Exception
else num
}
// retry function doesn't change
println(retry(5){myMethod(5,5000/*five seconds*/)})
/*
time goes on 5001
failed, retry #1
time goes on 5001
1
*/
println(retry(5){myMethod(-1,5000/*five seconds*/)})
/*
time goes on 5001
failed, retry #1
time goes on 5001
failed, retry #2
time goes on 5001
failed, retry #3
time goes on 5001
failed, retry #4
time goes on 5001
failed, retry #5
time goes on 5001
Exception in thread "main" java.lang.Exception
*/
我是 Scala 的新手。
我只想在超时时重试 code1
。如果再出现错误,我会换种方式处理。如果超时,我想再试一次,比如3次。这样做的正确方法是什么?
我不确定使用 code2
之类的东西是否是在 Scala 上执行此操作的最佳方式。也许已经有更好的东西了。有没有更清洁的破解方法?我应该使用 Await.ready 而不是结果吗?
我也不确定我是否应该使用 Await.ready 或 Await.result。
代码 1:
Await.result(myMethod(), Duration(120, "seconds"))
代码 2:
breakable {
for(_ <- 0 to 3) {
Try(Await.result(myMethod(), Duration(120, "seconds"))) match {
case Success(value) => {
// do something
break()
}
case Failure(_) => // how can I now if it is timeout?
}
}
}
您可以使用递归来实现简单的重试机制。匹配 TimeoutException
失败将使您能够专门处理超时情况。
下面是一个例子,假设 myMethod
returns 一个 Future[String]:
def myMethod(): Future[String] = ???
val maxAttempts = 3
def retryOnTimeout(attempt: Int = 0): String = {
Try(Await.result(myMethod(), Duration(120, "seconds"))) match {
case Success(result) => result
case Failure(_: TimeoutException) if attempt < maxAttempts => retryOnTimeout(attempt + 1)
case Failure(err) => throw err
}
}
retryOnTimeout
可以变得更通用,允许它在多个地方使用,函数作为参数传入。
等待 Future
会使整个 Future
变得毫无意义。也就是说,应该处理 3 种情况:
- 所有尝试都超时
- 一个non-time-out失败
- a
Future
成功完成
import scala.concurrent.duration._
import scala.concurrent.{Future, Await, TimeoutException}
import scala.util.{Try, Success, Failure}
// v--max number of attempts
LazyList.fill(4)(Try(Await.result(myMethod(), 120.seconds)))
.dropWhile{case Failure(_:TimeoutException) => true
case _ => false
}.headOption.fold{
//every attempt timed out
}{
case Success(value) => //do something
case Failure(ex:Throwable) => //ex is non-timeout exception
}
注意:LazyList
是 Scala 2.13.x 集合。列表中的每个元素只被评估 if/when 它是必需的,所以如果第一个成功,那么 none 其他期货将被启动。
您可以尝试将以下方法应用于 repeating evaluation
。
下面的代码片段定义了一个通用的 retry
方法:这个方法接受一个参数,在 try - catch
块中对其进行计算,并且 re-executes 它在失败时最大数量尝试。
让 retry
接受 by-name parameter
是允许它在必要时重复计算 myMethod block
的原因。
object Test {
def retry[T](max: Int)(f: => T): T = {
var tries = 0
var result: Option[T] = None
while (result == None) {
try {
result = Some(f)
}
catch {
case e: Throwable => tries += 1
if (tries > max) throw e
else {
println(s"failed, retry #$tries")
}
}
}
result.get
}
def myMethod(n: Int): Int = {
val num = scala.util.Random.nextInt(10)
if(n < num) throw new Exception
else num
}
def main(args: Array[String]): Unit = {
println(retry(max = 5){myMethod(3)})
/*
failed, retry #1
failed, retry #2
3
*/
println(retry(max = 5){myMethod(-1)})
/*
failed, retry #1
failed, retry #2
failed, retry #3
failed, retry #4
failed, retry #5
Exception in thread "main" java.lang.Exception
*/
}
}
注意
myMethod
函数可以采用新的参数超时来为每个函数调用引入一些时间限制。
def myMethod(n: Int, timeout: Long): Int = {
var num = scala.util.Random.nextInt(10)
val current = System.currentTimeMillis()
var running = System.currentTimeMillis()
while (running - current <= timeout && n < num) {
num = scala.util.Random.nextInt(10)
running = System.currentTimeMillis()
}
println(s"time goes on ${running - current}")
if(n < num) throw new Exception
else num
}
// retry function doesn't change
println(retry(5){myMethod(5,5000/*five seconds*/)})
/*
time goes on 5001
failed, retry #1
time goes on 5001
1
*/
println(retry(5){myMethod(-1,5000/*five seconds*/)})
/*
time goes on 5001
failed, retry #1
time goes on 5001
failed, retry #2
time goes on 5001
failed, retry #3
time goes on 5001
failed, retry #4
time goes on 5001
failed, retry #5
time goes on 5001
Exception in thread "main" java.lang.Exception
*/