ScalaTest中的afterAll()存在问题,以备将来使用

ScalaTest中的afterAll()存在问题,以备将来使用,scala,scalatest,Scala,Scalatest,在我的ScalaTest套件的末尾,我需要做一些DB清理。 清理工作本身就是一个未来。套件不调用super.afterAll,这使得套件使用的某些资源(如web浏览器和db连接)处于挂起状态 以下是相关代码: override def afterAll():Unit={ var cleanUpsInProgress = true DB.cleanUpDeletedSegments(db).onComplete{case _ => cleanUpsInProgre

在我的ScalaTest套件的末尾,我需要做一些DB清理。 清理工作本身就是一个未来。套件不调用super.afterAll,这使得套件使用的某些资源(如web浏览器和db连接)处于挂起状态

以下是相关代码:

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

我已经调试了一段时间,摸了摸头脑,得出结论,在未来的onComplete回调中,它甚至没有处理代码。即使我用存根Future.successfull1替换了Slick的db操作,我仍然拥有所有挂起的内容,super.afterAll未被调用。 也许我做错了什么愚蠢的事?你能帮忙吗

注意:我确实认为我需要在这里使用这个丑陋的var和while循环,因为否则主线程就会完成,启动运行套件的框架就会关闭JVM。也许我错了,所以如果能听到一些评论就好了

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

泰勒的解决方案有效。但是当我将一个异步清理映射到另一个实际需要执行的异步清理时,问题又是一样的。下面的代码冻结,不调用super.afterAll:

结果也不会抛出TimeoutException,从我所看到的情况来看,两者都没有正常完成。有什么想法吗

仅当我为每个未来依次使用wait.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()
}

等待将来的清理工作完成可能更容易:

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()
}

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

等待将来的清理完成可能更容易:

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提供的解决方案。您的解决方案不起作用,因为您使用了来自多个线程的非易失性变量CleanupProgress。

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

您的解决方案部分起作用。我已经更新了这个问题。你能回顾一下并分享一下你的想法吗?如果我不能描绘出另一个未来,那么一切都会按预期进行。第二个未来几乎是一样的,只是清理另一个db表,所以我不认为那里有什么特殊性。如果每个未来我都按顺序使用wait.result,它就会工作。真奇怪。我已经相应地更新了这个问题,可能其他人会对此有一些解释。您不想在生产代码中使用wait,但在测试中它是完全正确的,并且通常使事情更容易推理。有多个等待是可以的。我认为某些测试代码的重要性不亚于生产代码。但这不是重点。理解未来的标准组合器为什么会产生这样的结果会非常有趣。您的解决方案部分有效。我已经更新了这个问题。你能回顾一下并分享一下你的想法吗?如果我不能描绘出另一个未来,那么一切都会按预期进行。第二个未来几乎是一样的,只是清理另一个db表,所以我不认为那里有什么特殊性。如果每个未来我都按顺序使用wait.result,它就会工作。真奇怪。我已经相应地更新了这个问题,可能其他人会对此有一些解释。您不想在生产代码中使用wait,但在测试中它是完全正确的,并且通常使事情更容易推理。有多个等待是可以的。我认为某些测试代码的重要性不亚于生产代码。但这不是重点。了解未来标准组合器为什么会产生这样的结果真的很有意思。有没有方法在不阻塞wait.result的情况下实现结果?仅仅出于教育目的,最好知道如何以一种好的方式编写这样的代码。wait被认为是不好的,不是因为它以错误的方式等待。等待某件事本身就很糟糕。但是在您的测试中,这是可以的。顺便说一句,在循环期间将@volatile var cleanUpsInProgress=true插入Thread.sleep 100并没有任何区别。否则我会在星期一检查。有没有办法在不阻塞等待的情况下实现结果?仅仅出于教育目的,最好知道如何以一种好的方式编写这样的代码。wait被认为是不好的,不是因为它以错误的方式等待。等待某件事本身就很糟糕。但是在您的测试中,这是可以的。顺便说一句,在循环期间将@volatile var cleanUpsInProgress=true插入Thread.sleep 100并没有任何区别。否则我周一再查。
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()
}