2011-08-25 14 views
5

grailsアプリケーションで特定のタイプのバックグラウンド処理設定を作成しようとしています。grailsのバックグラウンドスレッドでHibernateを呼び出す

  • 固定サイズスレッドプールのみジョブ
  • のバッチの継続期間ため単一のセッションは、各ジョブは別のトランザクションで実行する各スレッド
  • によって維持され、存在

私は次のようにジョブを開始しようとしています:

int poolSize = 10 
ThreadFactory factory = new MyThreadFactory (Executors.defaultThreadFactory()) 
ExecutorService pool = Executors.newFixedThreadPool (poolSize, factory) 

(1..100).each { i -> 
    pool.submit { 
    try { 
     MyDomainClass.withTransaction { 
     doSomeWork(i) 
     } 
    } catch (Exception e) { 
     log.error "error in job ${i}", e 
    } 
    } 
} 

MyThreadFactory休止セッションを有しているスレッドがスレッドの期間添付作成します。

class MyThreadFactory implements ThreadFactory { 

    ThreadFactory delegate 
    PersistenceContextInterceptor persistenceInterceptor 

    MyThreadFactory (ThreadFactory delegate) { 
    this.delegate = delegate 
    ApplicationContext applicationContext = ApplicationHolder.getApplication().getMainContext() 
    persistenceInterceptor = applicationContext.getBean("persistenceInterceptor"); 
    } 

    Thread newThread (Runnable work) { 
    return delegate.newThread { 
     persistenceInterceptor.init() 
     try { 
     work.run() 
     } finally { 
     persistenceInterceptor.flush() 
     persistenceInterceptor.destroy() 
     } 
    } 
    } 
} 

しかし、私はバッチジョブを初めて実行するときに次のエラーが発生します。 (後続ジョブが問題なく実行)

groovy.lang.MissingMethodException: No signature of method: static MyDomainClass.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false]] 
Possible solutions: save(), save(java.util.Map), save(java.lang.Boolean), wait(), any(), wait(long) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
at ... 

ノー効果のMyDomainClass.withNewSession {}とpersitanceInterceptorを交換しようとしています。

GORMメソッドが私のドメインクラスに注入されていないかのように見えます。

私は何が間違っているのか誰にでも見ることができます。なぜバッチジョブを再度実行すると成功するのですか?完全のために @fixitagain

仕事は、この形式を取ります。

doSomeWork = { id -> 
    MyDomainClass a = MyDomainClass.findById (id) 
    a.value = lotsOfWork() 
    a.save() 
} 

私は保存行方不明は、私がトランザクションで動作をラップしようとしたとして、赤ニシンされ、その後 'というエラーを取得すると考えていますDomainClass.withTransaction(Closure) 'は定義されていません。

最初のジョブが実行に失敗する競合状態が発生する可能性がありますが、その後のすべてのジョブは(何か?)の起動後に正常に実行されるようです。

+0

どの時点でGrailsライフサイクルはあなたの仕事を始めていますか?ドメインがダイナミックメソッドなどで装飾される前に発生しているようです。 –

+0

ジョブはコントローラのアクション(現在は)からトリガされているため、ドメインが装飾された後です。メインスレッドからすべてのジョブを呼び出すと問題は発生しません。 – Akusete

+0

私にとって、GORMは可能な解決策としてsave(Map)を提案しているので、「添付」されています。保存している行を保存することはできますか? BTWのflushはデフォルトではfalseです。つまり、Hibernateセッションの終わりにフラッシュされます。 – fixitagain

答えて

1

独自のスレッドを作成するのではなく、Grails用のexecutorプラグインを使用することをお勧めします。それはあなたが作成するスレッドに必要なハイバネートセッションを注入します。また、それは使用するエグゼキュータ、スレッド数などに関して設定可能です。私はクォーツジョブや他のシナリオでプロダクションでそれを使用しています。

Grails Executor Plugin ご予約いただいている場合は、独自のスレッド戦略を作成する前にコードをご覧ください。

+0

executorプラグインを見てきました。また、persistenceInterceptorを使って新しいスレッドでセッションを作成します。現時点では、プラグインを使用する前にgrails/hibernateがどのように動作するかを完全に理解することにもっと興味があります。しかし、それに言及してくれてありがとう。 – Akusete

+0

エグゼキュータプラグインをもう一度見てから、ジョブごとに常に新しいセッションが作成されます。これは一般的には意味がありますが、私が後にしている特定のタスクには意味がありません。私はプラグインとしてセッションを作成するために全く同じメカニズムを使用しようとしています。 – Akusete

+0

Quartzプラグインを使用していないのはなぜですか? http://grails.org/plugin/quartz – felipenasc

0

コードや命名規則から分かりませんが、ドメインクラスのインスタンスでsaveを呼び出すことはできますか?

+0

私はそれがエラーメッセージで「奇妙な」ものだと思っていました。私は挑戦的にドメインクラスのインスタンスでsave()を呼び出しています。また、それが問題であれば、なぜ2回目の実行時にジョブが正常に終了するのか説明できません。 – Akusete

+0

a.save()を呼び出す前に、a = a.merge()が役に立ちますか? – bluesman

0

メソッドが見つからないということは、インスタンスではなくクラスでsaveを呼び出すことを意味します。

編集:GORMは、提案されているソリューションのメソッド名でわかるように、既に追加のメソッドを適用しています。

関連する問題