在 Future 使用的情况下,ScalaTest 中的 afterAll() 会出现问题

Problems with afterAll() in ScalaTest in case of Future usage

在我的 ScalaTest 套件结束时,我需要做一些数据库清理。 清理本身是一个 Future。该套件不会调用 super.afterAll(),这会留下套件使用的一些资源(如 Web 浏览器和数据库连接)待处理。

相关代码如下:

override def afterAll():Unit={
    var cleanUpsInProgress = true
    DB.cleanUpDeletedSegments(db).onComplete{case _ =>
      cleanUpsInProgress = false
    }
    while(cleanUpsInProgress){}
    db.close()
    aggregatesDB.close()
    super.afterAll()
  }

def cleanUpDeletedSegments(implicit db:ADMPDB):Future[Int]={
  db.run{
    segments.filter(_.deleted === 1).delete
  }
}

我已经调试并摸索了一段时间,得出的结论是它甚至没有处理未来 onComplete 回调中的代码。即使当我用存根 Future.successfull(1) 替换 Slick 的数据库操作时,我仍然有所有未决的事情并且 super.afterAll() 没有被调用。 可能我做错了什么愚蠢的事?你能帮忙吗?

注意:我确实认为我需要在此处使用这个丑陋的 varwhile 循环,否则主线程将完成并且启动套件的框架 运行 只是关闭 JVM。也许我在这里错了,所以很高兴听到一些评论。

------------------------更新-------------------- ----

Tyler 的解决方案有效。但是当我 flatMap 再进行一次异步清理(我实际上需要这样做)时,问题又是一样的。下面的代码冻结并且不调用 super.afterAll:

override def afterAll():Unit={
  val cleanUp = DB.cleanUpDeletedSegments(db).flatMap(_ => DB.cleanUpDeletedSegmentGroups(db))
  Await.result(cleanUp, 6 seconds)
  db.close()
  aggregatesDB.close()
  super.afterAll()
} 

Await.result 也不会抛出 TimeoutException 并且从我看来两者都没有正常完成。有什么想法吗?

只有当我像下面这样对每个未来顺序使用 Await.result 时它才有效:

override def afterAll():Unit={
  val cleanUpSegments = DB.cleanUpDeletedSegments(db)
  Await.result(cleanUpSegments, 3 seconds)
  val cleanUpSegmentGroups = DB.cleanUpDeletedSegmentGroups(db)
  Await.result(cleanUpSegmentGroups, 3 seconds)
  db.close()
  aggregatesDB.close()
  super.afterAll()
}

await 可能更容易完成 Future 清理工作:

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

override def afterAll() ={
  val future = DB.cleanUpDeletedSegments(db)
  Await.result(future, 2 minutes)
  aggregatesDB.close()
  super.afterAll()
}

您可以将超时设置为任何合理的值

使用@Tyler 的解决方案。您的解决方案无效,因为您使用了来自多个线程的非易失性变量 cleanupInProgress