2017-07-19 4 views
2

私はあなたの知恵を私と一緒に共有しようとしています、スカラパダン!削除呼び出しが完了するのを待ってからThread.sleepまたは接続を閉じる必要があるのはなぜですか?

私はscalaの反応型mongoで遊んでいますが、私はscalatestを使ってテストを書いていましたが、次の問題に直面しました。

まずコード:(コンストラクタの一部を)DBへの接続を初期化するコードを

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

だから私のテストパスを作るために、I削除が完了するのを待ってからすぐにThread.sleepを持っていなければなりませんでした。これを知っていることは、多くの鞭打ちによって通常処罰される悪であり、私は学び、適切な修正をここで見つける必要があります。

他のものを試したが、私は完全に私がここで誤解しています何

...また、トリックをしていたDBへの接続を閉じ、代わりに待機ましたか? dbへの接続は、それを呼び出すたびに開いて閉じるべきですか? 1つの接続でレコードを追加、削除、更新するなど、多くの操作を実行しないでください。

私の削除機能で読み取り呼び出しを削除すると、すべて正常に動作することに注意してください。また、接続を閉じることで、私はテストからMongoDriverをクローズし、私がバックグラウンドで使用しているMongoをやめてやり直すことを意味します。

お世話になりました。

答えて

2

警告:これは盲目的な推測ですが、ScalaのMongoDBに関する経験はありません。コレクションはので、この表現の実際の型はFuture[Future[WriteResult]]で、あなたのコードとremove戻りFuture[WriteResult]per docあたりFuture[BSONCollection]あるので

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

あなたは、このビットを見てみましょうflatMap

に忘れている可能性があります。

ここでは、戻り値Future[Unit]として関数に注釈を付けました。 Scalaは多くの場合、おそらく意味のある値を捨てることにより、戻り値として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() 

あなたはディスクについて警告することができますコンパイラフラグ(SBTを前提とします)を追加して値を計算します:

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

あなたは私の一日を作ったばかりです!それは期待どおりに動作しますありがとうございます。あなたの推測は正しかった。私はそれが削除を待っていないことを知っていたが、理由を理解できなかった。再びありがとう、私はスカラについてもう一度学びました。 – Jeep87c

関連する問題