Граалите. Не може да се установи връзка, басейнът е изчерпан

След като преработих един метод на услуга, за да използвам многопоточност, открих, че ако повече от един потребител се опитва да поиска страница (и да извика метод на услуга) много пъти, сървърът започва да хвърля изключение „Не може да се установи връзка, пулът е изчерпан“. Нека дам пример за моя клас на обслужване.

class DocumentService {
   def convertToJSON() {
      docs.collect { doc ->
         taskExecutor.submit({
            Document.withNewSession {
                def json = convertDocumentToJSON(doc)
            }
         } as Callable)
      }.collect { it.get() }
   }

   def convertDocumentToJSON(doc){
      def json = [:]
      // ... fill json with data using doc and GORM requests
      evaluateStatus(json)
      return json
   }

   def evaluateStatus(json){
      //... some work using database through GORM
   }
}

Боря се с този проблем повече от седмица и не мога да намеря решение. Не разбирам добре как Grails работи със сесии, връзки и транзакции. Моето предположение е следното. Когато се извика convertDocumentToJSON, той взема връзка от пула (4 потребители, 25 нишки на потребител = 100 връзки), но след това те трябва да извикат метода evaluateStatus, който също се опитва да получи връзка от пула за собствени нужди. Но пулът е изчерпан и никоя нишка не може да освободи връзка, защото всички те чакат evaluateStatus. Така че има задънена улица. Опитах се да поставя тип разпространение на SUPPORT за evaluateStatus, но получавам изключение „обединената връзка е затворена“. Тогава си помислих, че може да работи, ако преместя извикването на evaluateStatus от convertDocumentToJSON и написах такъв код

def convertToJSON(){
  docs.collect { doc ->
    taskExecutor.submit({
        Document.withNewSession {
            def json = convertDocumentToJSON(doc)
            evaluateStatus(json) // move call from convertDocumentToJSON
        }
      } as Callable)
  }.collect { it.get() }
}

но в този случай се сблъсках със същата грешка (изчерпан басейн). Моля, дайте ми съвет какво да коригирам в кода си


person volea    schedule 29.05.2017    source източник


Отговори (1)


Имате нужда от нещо, което да ограничи използването на връзки, опитайте да използвате GPars напр.

import groovyx.gpars.GParsPool

GParsPool.withPool() {
    docs.collect {
        // do your stuff...
    }
}

Има XXXXParallel версии на обичайните groovy методи за събиране, напр. collectParalle, с който можете да си поиграете, за да подпомогнете производителността.

person Mike W    schedule 29.05.2017
comment
Благодаря. Да, опитах да използвам GPars, но работи само с ForkJoinPool. Всъщност не помня какъв беше проблемът, но не оправда очакванията ми. И наистина съм любопитен какво не е наред с кода по-горе - person volea; 29.05.2017
comment
TaskExecutor Java ExecutorService ли е? Ако е така, колко голям е басейнът, с който е създаден? - person Mike W; 29.05.2017
comment
Да, това е ExecutorService. Размерът на басейна е 30. Пулът за връзка - 100 - person volea; 29.05.2017
comment
Колко време отнема да бъде хвърлено изключение? Изглежда, че пулът не чака дълго, след като всички връзки са били заети, преди да хвърли изключение, имате ли maxWait дефиниран във вашата конфигурация на dataSource? Стойността трябва да се дефинира в ms. - person Mike W; 29.05.2017
comment
Всички нишки са блокирани за 30 секунди и след това сървърът хвърля изключение. Съобщението казва, че не може да се установи връзка за 30 секунди. Мисля, че е стойност по подразбиране. Моят източник на данни няма дефинирана стойност maxWait. Ако поискам страница от един браузър, всичко е наред и методът отнема по-малко от секунда, за да завърши. - person volea; 30.05.2017