Закончились соединения SQL с Quarkus и hibernate-reactive-panache
У меня есть приложение Quarkus, которое использует hibernate-reactive-panache для выполнения некоторых запросов, а затем обрабатывает результат и возвращает JSON через вызов отдыха. Для каждого вызова Rest выполняется 5 запросов к БД, последний загрузит около 20 тыс. строк:
public Uni<GraphProcessor> loadData(GraphProcessor graphProcessor){
return myEntityRepository.findByDateLeaving(graphProcessor.getSearchDate())
.select().where(graphProcessor::filter)
.onItem().invoke(graphProcessor::onNextRow).collect().asList()
.onItem().invoke(g -> log.info("loadData - end"))
.replaceWith(graphProcessor);
}
//In myEntityRepository
public Multi<MyEntity> findByDateLeaving(LocalDate searchDate){
LocalDateTime startDate = searchDate.atStartOfDay();
return MyEntity.find("#MyEntity.findByDate",
Parameters.with("startDate", startDate)
.map()).stream();
}
Все это работает нормально в первые 4 раза, но на 5-м вызове я получаю
11:12:48:070 ERROR [org.hibernate.reactive.util.impl.CompletionStages:121] (147) HR000057: Failed to execute statement [$1select <ONE OF THE QUERIES HERE>]: $2could not load an entity: [com.mycode.SomeEntity#1]: java.util.concurrent.CompletionException: io.vertx.core.impl.NoStackTraceThrowable: Timeout
at <16 internal lines>
io.vertx.sqlclient.impl.pool.SqlConnectionPool$1PoolRequest.lambda$null$0(SqlConnectionPool.java:202) <4 internal lines>
at io.vertx.sqlclient.impl.pool.SqlConnectionPool$1PoolRequest.lambda$onEnqueue$1(SqlConnectionPool.java:199) <15 internal lines>
Caused by: io.vertx.core.impl.NoStackTraceThrowable: Timeout
Я проверил https://quarkus.io/guides/reactive-sql-clients#pooled-connection-idle-timeout и настроил quarkus.datasource.reactive.idle-timeout=1000.
Это само по себе не имело значения. Затем я добавил quarkus.datasource.reactive.max-size=10
Я смог выполнить 10 вызовов Rest, прежде чем снова получил тайм-аут. При настройке пула max-size=20 я смог запустить его 20 раз. Таким образом, похоже, что каждый вызов Rest будет использовать SQL-соединение, а не освобождать его снова.
Есть ли что-то, что нужно сделать, чтобы вручную разорвать соединение, или это просто ошибка?
1 ответ
Проблема заключалась в использовании @Blocking в реактивном методе Rest. См. https://github.com/quarkusio/quarkus/issues/25138 и https://quarkus.io/blog/resteasy-reactive-smart-dispatch/ для получения дополнительной информации.
Поэтому, если у вас есть метод rest, который возвращает, например, Uni или Multi, НЕ используйте @Blocking при вызове. Сначала мне пришлось добавить его, так как я получил исключение, сообщающее мне, что поток не может быть заблокирован. Это было связано с некоторыми интенсивными вычислениями ЦП. Добавление @Blocking устранило это исключение (в режиме разработки, но возникла другая проблема в основном режиме), но вызвало эту проблему с пулом SQL.
Реальное решение состояло в том, чтобы использовать emitOn для изменения потока для метода интенсивного использования процессора:
.emitOn(Infrastructure.getDefaultWorkerPool())
.onItem().transform(processor::cpuIntensiveMethod)