Grails StaleObjectStateException in lock() method Grails StaleObjectStateException in lock() method multithreading multithreading

Grails StaleObjectStateException in lock() method


We fixed 100% of our StaleStateException/OptimisticLocking issues by:

  • We don't explicitly lock anything. We adjusted the code flow and objects to minimize the chance of lock contention using the following
  • Removing all @Transactional annotations from all controllers. Move code that modifies domain objects from controllers into services. Never modify a domain object in a controller, ever. Only delegate to services (which are transactional by default) to modify domain objects. Perhaps you did this in this case, but make sure you do it 100% of the time.
  • Don't disable optimistic locking, it's there for a reason. Without it, you run the risk of overwriting an update from a different transaction. In general, you really need to know what you're doing if you're solving this problem with explicit locks or other interventions in the transaction processing.
  • Remember that if your domain object is part of a belongsTo/hasMany relationship, the version number of all of the related objects gets bumped up when any update occurs at all. So if two different processes are updating different parts of the object graph, the first to commit will invalidate the second and cause this. See if what Burt Beckwith is saying here is pertinent: https://www.youtube.com/watch?v=-nofscHeEuU. Even though he's talking about performance here, the solution he proposes also minimizes this cascading of version number updates.
  • Again, you don't appear to be doing this here, but we minimize passing potentially dirty whole domain objects around when we just need to do specific updates. So rather than orderService.update(order) when all we're doing is setting a status we might say orderService.setStatus('foo',orderId) and have that method do the get and update. This tightens the window of opportunity for a StaleState to occur because it's a short time from the fetch to the save. Basically, make sure you don't hang onto a dirty domain object longer than you absolutely have to.