2017-07-19 28 views
2

我再次寻求你与我分享你的智慧,斯卡拉padawan!为什么在等待删除呼叫完成后需要Thread.sleep或关闭连接?

我正在玩scala中的响应式mongo,当我使用scalatest写一个测试时,我遇到了以下问题。

首先代码:

"delete" when { 
    "passing an existent id" should { 
    "succeed" in { 
     val testRecord = TestRecord(someString) 
     Await.result(persistenceService.persist(testRecord), Duration.Inf) 

     Await.result(persistenceService.delete(testRecord.id), Duration.Inf) 
     Thread.sleep(1000) // Why do I need that to make the test succeeds? 

     val thrownException = intercept[RecordNotFoundException] { 
     Await.result(persistenceService.read(testRecord.id), Duration.Inf) 
     } 
     thrownException.getMessage should include(testRecord._id.toString) 
    } 
    } 
} 

而且读取和删除方法的代码初始化连接到数据库(构造函数的一部分):

class MongoPersistenceService[R](url: String, port: String, databaseName: String, collectionName: String) { 
    val driver = MongoDriver() 
    val parsedUri: Try[MongoConnection.ParsedURI] = MongoConnection.parseURI("%s:%s".format(url, port)) 
    val connection: Try[MongoConnection] = parsedUri.map(driver.connection) 
    val mongoConnection = Future.fromTry(connection) 
    def db: Future[DefaultDB] = mongoConnection.flatMap(_.database(databaseName)) 

    def collection: Future[BSONCollection] = db.map(_.collection(collectionName)) 
    def read(id: BSONObjectID): Future[R] = { 
     val query = BSONDocument("_id" -> id) 

     val readResult: Future[R] = for { 
     coll <- collection 
     record <- coll.find(query).requireOne[R] 
     } yield record 

     readResult.recover { 
     case NoSuchResultException => throw RecordNotFoundException(id) 
     } 
    } 
    def delete(id: BSONObjectID): Future[Unit] = { 
    val query = BSONDocument("_id" -> id) 

    // first read then call remove. Read will throw if not present 
    read(id).flatMap { (_) => collection.map(coll => coll.remove(query)) } 
    } 
} 

因此,为了使我的测试通不过,我在等待删除完成后,必须有一个Thread.sleep。知道这是邪恶通常会受到许多鞭打的惩罚,我想学习并找到适当的解决办法。

在尝试其他的东西,我发现的,而不是等待,完全关闭到数据库的连接也做的伎俩......

什么我误解吗?应该打开一个连接到数据库并关闭每次打电话给它?而不是执行许多操作,如使用一个连接添加,删除和更新记录?

请注意,当我删除我的删除功能中的读取呼叫时,一切正常。另外通过关闭连接,我的意思是在我的测试中关闭MongoDriver并停止并重新开始嵌入我在后台使用的Mongo。

感谢您的帮助。

回答

2

警告:这是一个盲目的猜测,我对于Scala上的MongoDB没有经验。

你可能已经忘记了flatMap

看看该位:

collection.map(coll => coll.remove(query)) 

由于收集Future[BSONCollection]根据您的代码和remove回报Future[WriteResult]per doc,这种表达的如此实际类型Future[Future[WriteResult]]

现在,你已经注释了你的函数返回Future[Unit]。斯卡拉常使Unit由扔掉可能有意义的值返回值,其中它在你的情况:

read(id).flatMap { (_) => 
    collection.map(coll => { 
    coll.remove(query) // we didn't wait for removal 
    ()     // before returning unit 
    }) 
} 

所以,你的代码也许应该是

read(id).flatMap(_ => collection.flatMap(_.remove(query).map(_ =>()))) 

还是一个for -comprehension:

for { 
    _ <- read(id) 
    coll <- collection 
    _ <- coll.remove(query) 
} yield() 

你可以让Scala警告你关于光盘通过添加一个编译器标志(假设SBT)带来了一个有价值的值:

scalacOptions += "-Ywarn-value-discard" 
+0

您刚刚度过了我的一天!谢谢它按预期工作。你的猜测是正确的。我知道它并没有等待删除,但不明白为什么。再次感谢你,我又学到了关于Scala的一些东西。 – Jeep87c