Закончились соединения 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)
Другие вопросы по тегам