Вызов Hibernate в фоновых потоках в Grails - PullRequest
5 голосов
/ 25 августа 2011

Я пытаюсь создать определенный тип настройки фоновой обработки в приложении Grails.

  • A фиксированный размер пул потоков существует только на время пакета заданий
  • A поддерживается один сеанс каждым потоком
  • Каждое задание выполняется в отдельной транзакции

Я пытаюсь запустить задание следующим образом:

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 ...

Я попытался заменить persitanceInterceptor на MyDomainClass.withNewSession {} , без эффекта.

Похоже, что GORMметоды не внедряются в классы моего домена.

Кто-нибудь может увидеть, что я делаю неправильно, и почему повторное выполнение пакетного задания позволяет ему успешно завершиться?

@ fixitagain Для полноты работы это выглядит следующим образом:

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

Я считаю, что отсутствующее сохранение - это красная сельдь, поскольку я попытался обернуть операцию в транзакции, а затем получил сообщение об ошибке «DomainClass.withTransactionЗакрытие) 'не определено.

Похоже, что может быть условие гонки, при котором не удается выполнить первое задание, но все последующие задания успешно выполняются после того, как ( что-то? ) завершило запускдо.

Ответы [ 3 ]

1 голос
/ 28 августа 2011

Вместо того, чтобы пытаться создать свой собственный поток, может быть целесообразно использовать плагин executor для Grails. Он внедряет необходимый сеанс гибернации в создаваемые вами потоки, а также настраивается в зависимости от используемого исполнителя, количества потоков и т. Д. Я использую его в работе с кварцевыми заданиями и другими сценариями, и он прекрасно работает.

Плагин Grails Executor Если у вас есть сомнения в его использовании, вы можете взглянуть на его код, прежде чем писать собственную стратегию потоков.

0 голосов
/ 01 сентября 2011

Исключение отсутствующего метода подразумевает, что вы вызываете save для класса, а не для экземпляра.

edit: GORM уже применил дополнительные методы, как вы можете видеть в именах методов предлагаемого решения.

0 голосов
/ 31 августа 2011

Я не могу разобрать код или соглашение об именах, но вы уверены, что вызываете save для экземпляра класса домена?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...