4

私のGrailsプロジェクト( grails 2.2.1 )でクォーツ(プラグイン:quartz2:2.1.6.2ですが、プラグイン:quartz:1.0-RC7でもテストしましたが、問題は変わりません)に問題があります。

こんなお仕事してます

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

}

}

execute メソッドで StaleObjectStateException が発生することがあります。これは私のロジックでは問題ありません。私は grails の楽観的ロックを使用しており、この例外は週に 1 回しか発生しません。

問題は、この例外が発生すると、ジョブが再び起動しなくなることです。

メソッドコードをtry catchでラップし、休止状態セッションを内部でフラッシュして、例外をキャプチャしようとしましたが、幸運はありませんでした。例外は、私のキャッチのいずれによってもキャプチャされません。

オンラインで調べてみると、これは古い Grails Quartz のバグであることがわかりましたが、修正されています。いずれにせよ、try{}catch を使用してバグを回避する必要があります。

PSジョブは、このタイプの呼び出しによってブートストラップからスケジュールされます

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)
4

3 に答える 3

1

古い投稿を復活させて申し訳ありませんが、最近レガシー Grails アプリ (Grails 2.2.3) でこの問題が発生し、execute メソッドでセッションをフラッシュしても問題が解決しない場合があるため、修正のために行ったことの概要を説明します。問題。

私たちの場合、execute メソッド内でセッションを明示的にフラッシュした場合でも、execute メソッドのコンテキスト外で例外が発生することがあります。具体的には、execute メソッドの実行が終了した後にセッションをフラッシュする Quartz2 プラグインの PersistenceContextJobListener コード内で例外がスローされます。そのため、Quartz2 プラグイン コードを確認した後、ジョブ実行メソッドをラップしてセッションをフラッシュするデフォルトの PersistenceContextJobListener をオーバーライドする必要があることに気付きました。

まず、PersistenceContextJobListener の jobWasExecuted コールバック メソッド内に例外処理がないことに注意してください。

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

実際に行う必要があるのは、独自のジョブ リスナーを実装し、jobWasExecuted コードを try/catch でラップすることだけです。これを行う方法の例については、次のコード スニペットを参照してください。

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

元の Quartz プラグインの SessionBinderJobListener を例として使用しました (エラー、多かれ少なかれコピーしました)。

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

とにかく、これにより、キャッチされていない StaleObjectStateException が原因で、トリガーされたジョブが完全に停止するのを防ぐことができるようになります。

于 2016-04-28T15:23:07.427 に答える
0

同様の問題に遭遇しました.Quartzジョブは、休止状態セッションがバインドされていないスレッドで実行されます.新しいセッションを取得してからflush()とclear()を強制することで回避できました。フラッシュしてクリアしないと、ジョブは最終的に以前のジョブ スレッドの 1 つを再利用し、同じオブジェクトを書き出そうとします (同じオブジェクトまたは同じクラスのオブジェクトである必要があるかどうかは思い出せません)。 、しかし、そのスレッドにバインドされたセッションにはコミットされていないコピーがあり、StaleObjectException が発生します。

私のコードは次のようになります。

def sessionFactory

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

    myDomain.save(flush: true)

    session.flush()
    session.clear()
}

サンプルコードで flush() と clear() を実行するだけで、同じ結果が得られる場合があります。

于 2013-06-20T14:16:23.700 に答える