Grails w/ GORM MongoDB plugin: org.grails.datastore.mapping.core.OptimisticLockingException

865 views Asked by At

I have a job that will run every few minutes, a new domain object is instantiated and populated with data from an api call, and then .save() is called to commit to the database.

This application uses the GORM Mongo plugin.

After deploying a new war to a test box, I received org.grails.datastore.mapping.core.OptimisticLockingException everytime the job kicked off and tried to process a file, make an api call, then save the results. The log (&error) points to the .save() call.

The error was being thrown after the log showed "Parsing file contents"

log.debug "Parsing file contents"
def map = [:]
def contents = new CsvParser().parse(fileContents, separator: '\t')
//Make a map of CSV contents
contents.each{ line ->
   map[line["name"]] = [:]
   line.columns.each{
      map[line["name"]][it.key[0].toLowerCase()+it.key.substring(1)]=line[it.key]
   }
   def thing = apiService.findThingDetailsByThingId(line["Thing_ID"].replaceAll( "[^\\d]", "" ))
   thing.save()
   map[line["name"]].putAll(thing.toMap())
}

The stacktrace below is probably overkill.

Heuristic completion: outcome state is rolled back; nested exception is org.springframework.transaction.TransactionSystemException: Could not commit Datastore transaction; nested exception is org.grails.datastore.mapping.core.OptimisticLockingException: The instance was updated by another user while you were editing
org.springframework.transaction.HeuristicCompletionException: Heuristic completion: outcome state is rolled back; nested exception is org.springframework.transaction.TransactionSystemException: Could not commit Datastore transaction; nested exception is org.grails.datastore.mapping.core.OptimisticLockingException: The instance was updated by another user while you were editing
   at org.grails.datastore.gorm.GormStaticApi.withNewSession(GormStaticApi.groovy:756)
   at grails.plugins.quartz.GrailsJobFactory$GrailsJob.execute(GrailsJobFactory.java:102)
   at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
   at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: org.springframework.transaction.TransactionSystemException: Could not commit Datastore transaction; nested exception is org.grails.datastore.mapping.core.OptimisticLockingException: The instance was updated by another user while you were editing
   at org.grails.datastore.mapping.transactions.DatastoreTransactionManager.doCommit(DatastoreTransactionManager.java:156)
   ... 8 more
Caused by: org.grails.datastore.mapping.core.OptimisticLockingException: The instance was updated by another user while you were editing
   at org.grails.datastore.mapping.mongo.engine.MongoEntityPersister$5.doInDB(MongoEntityPersister.java:664)
   at org.grails.datastore.mapping.mongo.engine.MongoEntityPersister.updateEntry(MongoEntityPersister.java:625)
   at org.grails.datastore.mapping.mongo.engine.MongoEntityPersister.updateEntry(MongoEntityPersister.java:82)
   at org.grails.datastore.mapping.engine.NativeEntryEntityPersister$2.run(NativeEntryEntityPersister.java:862)
   at org.grails.datastore.mapping.core.impl.PendingOperationExecution.executePendingOperation(PendingOperationExecution.java:33)
   at org.grails.datastore.mapping.core.AbstractSession.flushPendingOperations(AbstractSession.java:364)
   at org.grails.datastore.mapping.core.AbstractSession.flushPendingUpdates(AbstractSession.java:343)
   at org.grails.datastore.mapping.core.AbstractSession.flush(AbstractSession.java:263)
   at org.grails.datastore.mapping.mongo.MongoSession.flush(MongoSession.java:126)
   at org.grails.datastore.mapping.transactions.DatastoreTransactionManager.doCommit(DatastoreTransactionManager.java:151)
   ... 8 more
org.springframework.transaction.HeuristicCompletionException: Heuristic completion: outcome state is mixed; nested exception is org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
   at org.grails.datastore.gorm.GormStaticApi.withNewSession(GormStaticApi.groovy:756)
   at grails.plugins.quartz.GrailsJobFactory$GrailsJob.execute(GrailsJobFactory.java:102)
   at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
   at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
   ... 6 more

After trying tomcat restarts, checking mongo connections, etc. I resolved this behavior by dropping the domain object mongo collections (I had recently made a bunch of changes to the domain objects). Is it possible this error caused by changes to the domain object and a mongo/GORM data model conflict? If so, how can I avoid needing to drop collections in the future?

I don't believe it was possible that something else was accessing the same domain collection, and so don't think this was an optimistic locking exception, but if it was, what commands could I have run on the mongo side to see what connections were accessing that collection?

0

There are 0 answers