4

在我的Grails項目中,我有一個石英(plugin:quartz2:2.1.6.2,但我測試過插件:quartz:1.0-RC7,但問題沒有改變)(grails 2.2.1)。Quartz作業停止在StaleObjectStateException異常處執行

我有這樣的執行方法本

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

} 

} 

有時StaleObjectStateException occour工作。對於我的邏輯來說,這是可以的,我使用grails樂觀鎖,並且這種例外每週只發生一次。

問題是當這個異常發生時,Job停止再次發射。

我試着在try catch和flush hibernate session內部包裝方法代碼來捕獲異常但沒有財富。我的任何捕捉都沒有捕捉到這個例外。

在網上查找我發現這是一個old grails quartz bug但它是固定的,無論如何使用try {} catch必須繞過該錯誤。

P.S. 的作業從bootstrab通過這種類型的呼叫計劃

MyJob.schedule(10000L) 

是停止調度唯一的例外是

[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) 
+0

在你的代碼示例你不要再追「org.hibernate.StaleObjectStateException」,所以我想這是正常的工作失敗... – moskiteau 2013-05-14 13:06:31

+0

@moskiteau org.hibernate.StaleObjectStateException是org.hibernate.HibernateException – 2013-05-14 13:16:31

回答

1

對於恢復舊帖子我表示歉意,但我們最近在舊版Grails應用程序(Grails 2.2.3)中遇到了此問題,並且在執行方法中刷新了會話並不總是能解決問題,因此我將概述我們確實解決了這個問題。

在我們的例子中,即使我們在execute方法中顯式刷新會話,有時候這種異常也會發生在execute方法的上下文之外。更具體地說,拋出了Quartz2插件的PersistenceContextJobListener代碼中的異常,該代碼在執行完execute方法後刷新會話。因此,在查看了Quartz2插件代碼之後,我們意識到我們需要重寫默認的PersistenceContextJobListener,它包裝作業execute方法並刷新會話。

首先,請注意,PersistenceContextJobListener的jobWasExecuted回調方法中沒有異常處理。

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

你真正需要做的是實現自己的工作聽衆在一個try/catch包裹jobWasExecuted代碼。有關如何執行此操作的示例,請參閱以下代碼片段。

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

我們使用的原始石英插件的SessionBinderJobListener爲例(ERR,我們或多或少複製它)。

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

無論如何,這應該讓你到你在哪裏防止觸發工作從完全停止的地步,由於未捕獲StaleObjectStateException。

+0

偉大的工作Justin。我不再在這個項目上工作,我無法測試解決方案,但對我來說似乎很好。 – 2016-04-29 07:40:09

0

不知道你的例子如何準確的,但你要知道,常規正在打包異常。這意味着即使在代碼拋出StaleObjectStateException時,也可以用簡單的RuntimeException封裝它,這在上面沒有提到。 myDomain.save(flush: true)方法(直接工作或從其他服務執行)有多深?

0

我碰到類似的問題,石英作業運行在一個沒有綁定hibernate會話的線程上,我可以通過抓住一個新的會話然後強制flush()和a明確()。如果你沒有清除&清除作業最終將重新使用以前的工作線程之一,並嘗試寫出相同的對象(不能回想起來,如果它必須是同一類或同一類的任何對象) ,但會有在綁定到該線程的會話的未提交副本,這將反過來導致StaleObjectException異常:

這裏是我的代碼如下所示:

def sessionFactory 

def execute() { 
    def session = SessionFactoryUtils.getSession(sessionFactory,true) 

    myDomain.save(flush: true) 

    session.flush() 
    session.clear() 
} 

您可能只需要在示例代碼中執行flush()和clear()以獲得相同的結果。

+0

Thanl你miedzial。用齊平和清晰的嘗試。問題不在於我的項目假設的StaleObjectException。問題是,當StaleObjectException出現時,我無法捕捉它,石英停止執行其他調用 – 2013-06-24 08:00:06