Michael Bar-Sinai
Michael Bar-Sinai

Reputation: 2739

ReactiveMongo/Play: `LastError: DatabaseException['<none>']`, while db still updates

weird problem: While my play application tries to insert/update records from some mongoDB collections while using reactivemongo, the operation seems to fail with a mysterious message, but the record does, actually, gets inserted/updated.

More info:

  1. Insert to problematic collections from the mongo console works well
  2. reading from all collections works well
  3. reading and writing to other collections in the same db works well
  4. writing to the problematic collections used to work.

Error message is:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[LastError: DatabaseException['<none>']]]
  at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:280)
  at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:206)
  at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:100)
  at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
  at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:344)
  at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:343)
  at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
  at play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:70)
  at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40)
  at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248)
Caused by: reactivemongo.api.commands.LastError: DatabaseException['<none>']

Using ReactiveMongo 0.11.14, Play 2.5.4, Scala 2.11.7, MongoDB 3.4.0.

Thanks!

UPDATE - The mystery thickens!

Based on @Yaroslav_Derman's answer, I added a .recover clause, like so:

collectionRef.flatMap( c =>
  c.update( BSONDocument("_id" -> publicationWithId.id.get), publicationWithId.asInstanceOf[PublicationItem], upsert=true))
  .map(wr => {
    Logger.warn("Write Result: " + wr )
    Logger.warn("wr.inError: " + wr.inError)
    Logger.warn("*************")
    publicationWithId
  }).recover({
  case de:DatabaseException => {
    Logger.warn("DatabaseException: " + de.getMessage())
    Logger.warn("Cause: " + de.getCause())
    Logger.warn("Code: " + de.code)
    publicationWithId
  }
})

The recover clause does get called. Here's the log:

[info] application - Saving pub t3
[warn] application - *************
[warn] application - Saving publication     Publication(Some(BSONObjectID("5848101d7263468d01ff390d")),t3,2016-12-07,desc,auth,filename,None)
[info] application - Resolving database...
[info] application - Resolving database...
[warn] application - DatabaseException: DatabaseException['<none>']
[warn] application - Cause: null
[warn] application - Code: None

So no cause, no code, message is "'<none>'", but still an error. What gives?

I tried to move to 0.12, but that caused some compilation errors across the app, plus I'm not sure that would solve the problem. So I'd like to understand what's wrong first.

UPDATE #2: Migrated to reactive-mongo 0.12.0. Problem persists.

Upvotes: 1

Views: 1451

Answers (3)

Michael Bar-Sinai
Michael Bar-Sinai

Reputation: 2739

Problem solved by downgrading to MongoDB 3.2.8. Turns out reactiveMongo 0.12.0 is not compatible with mongoDB 3.4.

Thanks everyone who looked into this.

Upvotes: 7

Yaroslav Derman
Yaroslav Derman

Reputation: 51

For play reactivemongo 0.12.0 you can do like this

def appsDb = reactiveMongoApi.database.map(_.collection[JSONCollection](DesktopApp.COLLECTION_NAME))

def save(id: String, user: User, body: JsValue) = {
    val version = (body \ "version").as[String]
    val app = DesktopApp(id, version, user)

    appsDb.flatMap(
      _.insert(app)
        .map(_ => app)
        .recover(processError)
    )
  }

def processError[T]: PartialFunction[Throwable, T] = {
    case ex: DatabaseException if ex.code.contains(10054 | 10056 | 10058 | 10107 | 13435 | 13436) =>
      //Custom exception which processed in Error Handler
      throw new AppException(ResponseCode.ALREADY_EXISTS, "Entity already exists")

    case ex: DatabaseException if ex.code.contains(10057 | 15845 | 16550) =>
      //Custom exception which processed in Error Handler
      throw new AppException(ResponseCode.ENTITY_NOT_FOUND, "Entity not found")

    case ex: Exception =>
      //Custom exception which processed in Error Handler
      throw new InternalServerErrorException(ex.getMessage)
  }

Also you can add logs in processError method

Upvotes: 2

Andriy Kuba
Andriy Kuba

Reputation: 8263

LastError was deprecated in 0.11, replaced by WriteResult.

LastError does not, actually, means error, it could mean successful result, you need to check inError property of the LastError object to detect if it's real error. As I see, the '<none>' error message give a good chance that this is not error.

Here is the example "how it was in 0.10": http://reactivemongo.org/releases/0.10/documentation/tutorial/write-documents.html

Upvotes: 1

Related Questions