在 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()
没有被调用。
可能我做错了什么愚蠢的事?你能帮忙吗?
注意:我确实认为我需要在此处使用这个丑陋的 var
和 while
循环,否则主线程将完成并且启动套件的框架 运行 只是关闭 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
。
在我的 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()
没有被调用。
可能我做错了什么愚蠢的事?你能帮忙吗?
注意:我确实认为我需要在此处使用这个丑陋的 var
和 while
循环,否则主线程将完成并且启动套件的框架 运行 只是关闭 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
。