digital-garden/dev/snippet/Проблема с Hibernate Reactive в Telegram SDK для Java.md

4.4 KiB
Raw Blame History

aliases tags date zero-link parents linked
maturity/🌱
2024-09-11
../../meta/zero/00 Java разработка

В моей библиотеке по конструированию Telegram ботов при переходе на ../../meta/zero/00 Quarkus возникала проблема.

Проблема возникает при вызове метода в библиотеке телеграма AbsSender.executeAsync(). Судя по всему сессии БД зависают и не освобождаются, из-за чего пул сессий заканчивается и возникает следующее исключение:

024-09-11 11:25:05,060 ERROR [io.qua.arc.imp.AbstractInstanceHandle] (pool-12-thread-1) Error occurred while destroying instance of bean [io.quarkus.hibernate.reactive.runtime.ReactiveSessionProducer_ProducerMethod_createMutinySession_1321d110ee9e92bda147899150401e0a136779c7_Bean]: java.util.concurrent.CompletionException: java.lang.IllegalStateException: HR000069: Detected use of the reactive Session from a different Thread than the one which was used to open the reactive Session - this suggests an invalid integration; original thread [186]: 'vert.x-eventloop-thread-5' current Thread [189]: 'vert.x-eventloop-thread-6'

Проблема в том, что в DefaultAbsSender есть поле protected final ExecutorService exe, который используется в AbsSender.executeAsync(). Этот ExecutorService никак не изменить, в конструктор не передать, сеттера нет, да и поле final.

Эта особенность приводит к тому, что при использовании вызовов телеграм в контексте работы с ../../meta/zero/00 Hibernate Reactive мы получаем ситуацию, в которой ../fundamental/Поток процесса ОС меняется. ../../meta/zero/00 Hibernate Reactive в свою очередь требует, чтобы вся работа выполнялась в рамках одного и того же ../fundamental/Поток процесса ОС из-за особенностей управления сессиями и транзакциями.

В документации четко сказано: "Сеанс не является потокобезопасным (или "потокобезопасным"), поэтому его использование в разных потоках (или реактивных потоках) может привести к ошибкам, которые крайне трудно обнаружить. Не говорите, что мы вас не предупреждали!"

Решением данной ситуации для своей библиотеки я нашел в следующем. У меня есть TelegramPollingBot, который является наследником DefaultAbsSender, поэтому в конструкторе я получаю доступ к final полю через ../java/Java Reflection, далее делаю его изменяемым и устанавливаю ExecutorService.

final Field field = this.getClass().getSuperclass().getSuperclass().getDeclaredField("exe");  
// Делаем поле exe доступным для изменений  
field.setAccessible(true);  
// Заменяем поле exe в экземпляре наследника  
field.set(this, Infrastructure.getDefaultWorkerPool());  
// Закрываем доступ к полю exe  
field.setAccessible(false);

Мета информация

Область:: ../../meta/zero/00 Снипеты для Java Родитель:: Источник:: Создана:: 2024-09-11 Автор::

Дополнительные материалы