Quartz job terminates StaleObjectStateException

I have a problem with quartz (plugin: quartz2: 2.1.6.2, but I have a test even with the plugin: quartz: 1.0-RC7, but the problem does not change) in my Grails project (grails 2.2.1).

I have such a job

class MyJob { def concurrent = false def execute(context){ try { //.... // works with domains ..... myDomain.save(flush: true) // works with domains ..... //.... sessionFactory.currentSession.flush() } catch (org.springframework.dao.OptimisticLockingFailureException olfe) { println "Job failed by database exception " } catch ( org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException ole){ println "Job failed by database exception " } catch ( org.hibernate.HibernateException hibe ){ println "Job failed by database exception " } } } } 

Sometimes the execution method uses a StaleObjectStateException. This is normal for my logic, I use optimistic grails lock, and this exception occurs only once a week.

The problem is when this exception occurs when Job stops starting again.

I tried co wrap method code in try catch and flush hibernate session inside to catch an exception, but without fortune. An exception is not capture by any of my catch.

In an online search, I found this an old grails quartz error , but it has been fixed, and in any case, using try {} catch should get around the error.

PS The task is scheduled from bootstrab by calling this type

 MyJob.schedule( 10000L ) 

The exception that stops planning is

 [194949896] core.ErrorLogger Unable to notify JobListener(s) of Job that was executed: (error will be ignored). trigger= DEFAULT.MT_3tbn6lewgiqa3 job= DEFAULT.MyJob org.quartz.SchedulerException: JobListener 'persistenceContextJobListener' threw exception: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [MyDomain#42] [See nested exception: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [MyDomain#42]] at org.quartz.core.QuartzScheduler.notifyJobListenersWasExecuted(QuartzScheduler.java:1939) at org.quartz.core.JobRunShell.notifyJobListenersComplete(JobRunShell.java:361) at org.quartz.core.JobRunShell.run(JobRunShell.java:235) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557) Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [MyDomain#42] at grails.plugin.quartz2.PersistenceContextJobListener.jobWasExecuted(PersistenceContextJobListener.groovy:46) at org.quartz.core.QuartzScheduler.notifyJobListenersWasExecuted(QuartzScheduler.java:1937) ... 3 more ..... events.PatchedDefaultFlushEventListener Could not synchronize database state with session org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [MyJob#42] at MyJob.execute(MyJob.groovy:354) at grails.plugin.quartz2.GrailsArtefactJob.execute(GrailsArtefactJob.java:57) at org.quartz.core.JobRunShell.run(JobRunShell.java:213) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557) 
+4
source share
3 answers

I apologize for restoring the old message, but we ran into this issue with the outdated Grails application (Grails 2.2.3) recently, and clearing the session in the execution method did not always solve the problem, so I will describe what we did to solve the problem.

In our case, sometimes an exception may occur outside the context of the execute method, even if we explicitly dropped the session in the execute method. More specifically, an exception is thrown in the Quartz2 PluginsContextJobListener code, which resets the session AFTER the execution method completes. Therefore, after looking at the Quartz2 plugin code, we realized that we need to override the default PersistenceContextJobListener value, which completes the task execution method and clears the session.

First, note the lack of exception handling in the jobWasExecuted callback method for PersistenceContextJobListener.

https://github.com/9ci/grails-quartz2/blob/master/src/groovy/grails/plugin/quartz2/PersistenceContextJobListener.groovy#L44

All you really need to do is implement your own job listener and wrap the jobWasExecuted code in try / catch. See the following code snippets for an example of how to do this.

https://gist.github.com/jmiranda/45084eb32f07f6e3d1934547cd4fbb9f https://gist.github.com/jmiranda/5148f0a67afc8950bad950793e9c2303

As an example, we used the original Quartz plugin SessionBinderJobListener (err, we copied it more or less).

https://github.com/grails-plugins/grails-quartz/blob/master/src/main/groovy/grails/plugins/quartz/listeners/SessionBinderJobListener.java

In any case, this should lead you to the fact that you prevent the launch of running tasks in general due to the unreported StaleObjectStateException.

+1
source

I don't know how accurate your example is, but you need to know that groovy is an exception to the wrapping. This means that even when the code fires a StaleObjectStateException, you can get it in a simple RuntimeException, which is not caught above. How deep is this myDomain.save(flush: true) method (right in the job or executed from another service)?

0
source

I ran into a similar problem, the quartz job runs in a thread that is not connected to it by a sleep session, I managed to get around it, capturing a new session, and then force the flash () and clear (). If you don’t clear and clear the task, eventually repeat using one of the previous tasks and try to write out the same object (you cannot remember whether it should be the same or any object of the same class), but the session will contain an incorrect the copy associated with this thread, which in turn will throw a StaleObjectException:

This is what my code looks like:

 def sessionFactory def execute() { def session = SessionFactoryUtils.getSession(sessionFactory,true) myDomain.save(flush: true) session.flush() session.clear() } 

You may need to do flush () and clear () in your sample code to achieve the same result.

0
source

Source: https://habr.com/ru/post/1479322/


All Articles