我正在尝试记录每个任务的经过时间,如下所示。
我遇到的问题是 logElapsedTime 中的回调方法由于某种原因永远不会被调用。
仅调用对Future f 的最后一个回调。
如何解决此问题,以便正确记录每个经过的时间?
def logElapsedTime[T](f: Future[T], description: String): Future[T] = {
val start = System.currentTimeMillis()
f onComplete (_ => logger.debug(s"$description took [${System.currentTimeMillis() - start}]"))
f
}
val f = for {
_ <- logElapsedTime(task1(), "1st task to be executed")
result <- logElapsedTime(task2(), "2nd task to be executed")
_ <- logElapsedTime(task3(), "3rd task to be executed")
_ <- logElapsedTime(task4(), "4th task to be executed")
} yield result
f onComplete {
case Success(v) =>
logger.info(s"tasks succeeded !!!! $v")
case Failure(ex) =>
logger.error(ex.getMessage)
throw ex
}
输出样本↓
成功时:
任务成功!!!!一些价值
失败时:
一些错误消息
不记录其他任何输入。
(日志级别设置为debug及以上)
答案 0 :(得分:3)
您的逻辑没有错。我建议您尝试一下的修改很少。
import org.slf4j.LoggerFactory
import scala.concurrent.Future
import concurrent.ExecutionContext.Implicits.global
import scala.io.StdIn
import scala.util.{Failure, Success}
object FutureOnComplete extends App {
private val logger = LoggerFactory.getLogger("test")
def logElapsedTime[T](f: => Future[T], description: String): Future[T] = {
val start = System.currentTimeMillis()
f.onComplete(
_ =>
logger.warn(
s"$description took [${System.currentTimeMillis() - start}]"))
f
}
val f = for {
_ <- logElapsedTime(Future(1), "1st task to be executed")
result <- logElapsedTime(Future(2), "2nd task to be executed")
_ <- logElapsedTime(Future(2), "3rd task to be executed")
_ <- logElapsedTime(Future(2), "4th task to be executed")
} yield result
f.onComplete {
case Success(v) =>
logger.info(s"tasks succeeded !!!! $v")
case Failure(ex) =>
logger.error(ex.getMessage)
throw ex
}
StdIn.readLine()
}
warn
,以确保不会归咎于您的日志记录。或将其替换为println
StdIn.readLine()
的将来完成。这样可以使异步进程完成并运行onComplete。=> Future[T]
的名称参数在方法logElapsedTime
中开始执行future。这只是在未来开始时发生变化,而不是日志记录的逻辑答案 1 :(得分:3)
例如,当我们只想作为副作用执行日志记录而不转换Future
内的值时,请考虑andThen
object futureAndThenLogging extends App with LazyLogging {
def logElapsedTime[T](f: Future[T], description: String): Future[T] = {
val start = System.currentTimeMillis()
f andThen { case _ => logger.debug(s"$description took [${System.currentTimeMillis() - start}]") }
}
def task1() = Future(1)
def task2() = Future(2)
def task3() = Future(3)
def task4() = Future(4)
(for {
_ <- logElapsedTime(task1(), "1st task to be executed")
result <- logElapsedTime(task2(), "2nd task to be executed")
_ <- logElapsedTime(task3(), "3rd task to be executed")
_ <- logElapsedTime(task4(), "4th task to be executed")
} yield result)
.andThen {
case Success(v) => logger.info(s"tasks succeeded !!!! $v")
case Failure(ex) => logger.error(ex.getMessage)
}
Thread.sleep(1000) // just for demonstration purposes
}
请注意,我们不必重新throw ex
中的case Failure(ex) => logger.error(ex.getMessage)
。