АРХИВ ПО ТЭГУ "DB"
АПРЕЛЬ 17, 2015

Just a note on how to get running time for a query defined by regex:

  1. SELECT datname,waiting,now()-query_start,current_query
  2. FROM pg_stat_activity
  3. WHERE current_query ilike '%YOUR QUERY REGEX GOES HERE%'
  4. ORDER BY procpid;
НОЯБРЬ 8, 2012

Hi,

Рябы рябские, как дела?

Меня тут вдруг запарила проблема с оптимистик локинг фейлур (StaleObjectStateException, OptimisticLockingFailureExceptionHibernateOptimisticLockingFailureException) в Grails, когда слишком частые запросы на сервер приводят к синхронному обновлению домена в персистенс, что в свою очередь приводит к падению одного из запросов, т.к. version уже обновлен другим потоком (запросом). Собсно я  решил написать небольшой хелпер для сохранения доменов, в  итоге это оказало не хелпером, а заижекченым методом во все доменные классы проекта. Ща покажу как это юзается, а потом уже саму имплементацию.

Домен

  1. // по дефолту в грейлс каждый домен
  2. // юзает optimistic locking, используя
  3. // version колонку (проперти)
  4. class Something {
  5.   String name
  6.   String value
  7. }

Стандартное сохранение домена

  1. // загружаем и обновляем значение
  2. def e = Something.get(1)
  3.  
  4. // если в этот момент другой запрос (поток) обновит
  5. // эту запись, то грейлс кинет StaleObjectStateException
  6. e.value = "asdasd"
  7. e.save flush: true, failOnError: true

Сохранение с optimistic locking with retry вариант 1

  1. // загружаем и обновляем
  2. def e = Something.get(1)
  3.  
  4. // если в этот момент другой  запрос (поток) обновит
  5. // эту запись, то мы рефрешнем запись в сессии и
  6. // попробуем обновить еще разок
  7. e.saveOptimisticWithRetry flush: true, failOnError: true, retryCount: 2, { obj ->
  8.   obj.value = "asd"
  9. }

Сохранение с optimistic locking with retry вариант 2

  1. // все параметры опциональны, их можно опустить
  2. // по дефолту:
  3. // retryCount = 2
  4. // flush = false
  5. // failOnError = true
  6. def e = Something.get(1)
  7. e.saveOptimisticWithRetry retryCount: 5, { obj ->
  8.   obj.value = "asd"
  9. }

Сохранение с optimistic locking with retry вариант 3

  1. // все параметры опциональны, их можно опустить
  2. def e = Something.get(1)
  3. e.saveOptimisticWithRetry { obj ->
  4.   obj.value = "asd"
  5. }

Имплементация optimistic locking with retry

  1. // в Bootstrap.groovy к примеру можно
  2. // заинжектить метод во все домены
  3. for (dc in grailsApplication.domainClasses) {
  4.   dc.metaClass.saveOptimisticWithRetry = { args = null, setter ->
  5.     final int retryCount = args?.containsKey('retryCount') ? args.retryCount : 2
  6.     final boolean failOnError = args?.containsKey('failOnError') ? args.failOnError : true
  7.     final boolean flush = args?.containsKey('flush') ? args.flush : true
  8.    
  9.     int i = 0
  10.     while (true) {
  11.       try {
  12.         // Save domain
  13.         setter(delegate)
  14.         delegate.save(failOnError: failOnError, flush: flush)
  15.         return
  16.       }
  17.       catch (StaleObjectStateException e) {
  18.         // Throw exception if retry count bounds reached
  19.         if (++i > retryCount) {
  20.           throw e
  21.         }
  22.        
  23.         // Refresh object within session
  24.         delegate.refresh()
  25.       }
  26.     }
  27.   }
  28. }

Хорошего дня!

PS Можно вобщем-то подменить и сам метод save() у доменов, добавив в него имплементацию ретрая при оптимистик логинг фейлуре ексепшене.