Метод TransactionAttributeType.NOT_SUPPORTED тратит время транзакции приостановленной транзакции

У меня есть метод, который выполняет тяжелые операции (обработка файлов), который не требует транзакции, но находится внутри нее и генерирует тайм-ауты. У меня нет возможности реорганизовать код или увеличить время ожидания транзакции по умолчанию. Я попытался использовать TransactionAttributeType.NOT_SUPPORTED в методе обработчика файлов, чтобы временно приостановить транзакцию, но он продолжает считать время, пока он приостановлен, и продолжает давать мне тайм-аут.

Такой способ работы правильный? Когда транзакция приостановлена, время транзакции все еще тратится?

Я сделал следующий пример приближения с той же проблемой. Код:

@Slf4j
@Stateless
public class Foo1 {

    @Inject
    Foo2 foo2;

    @PersistenceContext
    EntityManager em;

    @TransactionTimeout(value= 10, unit = TimeUnit.SECONDS)
    public void saveWith10secondsTimeout() {
        log.info("Start Foo1");
        Foo entity = new entity();
        em.persist(entity);
        foo2.threadSleep15seconds();
        log.info("End Foo1");
    }
}

@Slf4j
@Stateless
@TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
public class Foo2 {
    public void threadSleep15seconds() {
        log.info("Start Foo2");
        try {
            Thread.sleep(15 * 1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("End Foo2");
    }
}

Вызов диспетчера:

@Inject
Foo1 foo1;

@GET
@Path("/foo-not-supported")
@TransactionAttribute(TransactionAttributeType.NEVER)
public Response testNotSupported() {
    log.info("Start testNotSupported");
    foo1.saveWith10secondsTimeout();
    return Response.status(OK).build();
}

Журналы:

15:00:30,867 INFO  [com.FooController] (default task-1) Start testNotSupported
15:00:30,868 INFO  [com.Foo1] (default task-1) Start Foo1
15:00:30,883 INFO  [com.Foo2] (default task-1) Start Foo2
15:00:40,867 INFO  [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check timeout for TX 0:ffff7f000101:-441cac6:64394e3c:382 in state  RUN
15:00:40,877 INFO  [org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorTrackingImpl] (Transaction Reaper Worker 0) HHH000451: Transaction afterCompletion called by a background thread; delaying afterCompletion processing until the original thread can handle it. [status=4]
15:00:40,881 INFO  [com.arjuna.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012121: TransactionReaper::doCancellations worker Thread[Transaction Reaper Worker 0,5,main] successfully canceled TX 0:ffff7f000101:-441cac6:64394e3c:382
15:00:45,884 INFO  [com.Foo2] (default task-1) End Foo2
15:00:45,884 INFO  [com.Foo1] (default task-1) End Foo1
15:00:45,884 INFO  [com.arjuna.ats.arjuna] (default task-1) ARJUNA012077: Abort called on already aborted atomic action 0:ffff7f000101:-441cac6:64394e3c:382
15:00:45,887 ERROR [org.jboss.as.ejb3.invocation] (default task-1) WFLYEJB0034: EJB Invocation failed on component Foo1 for method public void com.Foo1.saveWith10secondsTimeout(): javax.ejb.EJBTransactionRolledbackException: javax.transaction.RollbackException: WFLYEJB0447: Transaction 'Local transaction (delegate=TransactionImple < ac, BasicAction: 0:ffff7f000101:-441cac6:64394e3c:382 status: ActionStatus.ABORTED >, owner=Local transaction context for provider JBoss JTA transaction provider)' was already rolled back

Я надеюсь, что эта транзакция может удерживать блокировки, препятствующие завершению других транзакций. Не лучше держать транзакции открытыми в течение длительного времени, и просто возможность отключить транзакцию ничего не делает для освобождения ее блокировок и продолжения других процессов. С какой именно целью вы приостанавливаете транзакцию?

Chris 14.04.2023 20:13

@Chris Цель приостановки транзакции состояла в том, чтобы избежать тайм-аута, некоторые процессы, обрабатывающие файлы, близки к пяти минутам (в примере это будет метод threadSleep15seconds), и они генерируют тайм-аут в транзакции, но операция с файлом проведен правильно. Идея заключалась в том, чтобы использовать NOT_SUPPORTED, чтобы это время не добавлялось ко времени транзакции, но либо я его не правильно использую, либо оно так не работает и у меня не будет выбора, кроме как увеличить таймаут транзакции или рефакторить код .

oscar 15.04.2023 15:41

При использовании TransactionAttributeType.NOT_SUPPORTED текущие транзакции приостанавливаются во время выполнения метода и возобновляются после завершения. Тайм-аут транзакции все еще работает, поэтому, если он истекает до завершения метода, транзакция откатывается. В этом случае транзакция откатывается до завершения метода, потому что Foo2.threadSleep15seconds() занимает больше 10-секундного времени ожидания, установленного для Foo1.saveWith10secondsTimeout(). Вы можете увеличить значение времени ожидания или обрабатывать файловые операции асинхронно или небольшими порциями, если вы не можете изменить код.

Raj Raj 16.04.2023 23:11
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
103
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Кажется, здесь есть какая-то проблема с дизайном.

Foo2.threadSleep15seconds(), похоже, имитирует длительный файловый процесс, о котором вы говорите. Насколько тесно эта обработка файла связана с текущей транзакцией БД?

Если у вас может быть какое-то отдельное управление состоянием, то, как часть Foo1.saveWith10secondsTimeout(), вы можете просто вставить запись в таблицу БД, которая обрабатывает файл pending. И вернуть сразу, чтобы сделка не задержалась на долгий срок.

Создайте отдельный поток (асинхронное выполнение Foo2.threadSleep15seconds()) для обработки всех файлов, которые будут обрабатываться всеми запросами, сделанными к Foo1.saveWith10secondsTimeout(). Этот поток (или пул потоков) будет продолжать обрабатывать файлы и изменять статус этих файлов в таблице БД с pending на done или error в зависимости от результата, а затем запускать следующий процесс на основе результата.

Но если одна транзакция задерживается до тех пор, пока не будут обработаны все файлы, это определенно заблокирует некоторые другие действия в другом месте.

Ответ принят как подходящий

Тайм-аут транзакции означает, что транзакция может быть отменена, если она все еще активна по истечении периода. Приостановка транзакции не влияет на тайм-аут (поскольку это противоречит цели установки тайм-аута).

Другие вопросы по теме

Таблица соединения JPA с несколькими столбцами для разных коллекций
Утечка соединения Spring/Hibernate с помощью ScrollableResults
Как я могу заставить JPA hibernate не добавлять значение NULL, когда поле не установлено (null), при вставке в поле значения по умолчанию db/2
Java.lang.NullPointerException в org.hibernate.hql.internal.NameGenerator.generateColumnNames(NameGenerator.java:27)
Ошибка «Невозможно найти персистент» с пакетом Spring + Hibernate ORM
Не удалось загрузить запрошенный класс: org.hibernate.orm:hibernate-community-dialects для sqlite
Почему свойство CascadeType Hibernate работает только для дочерних элементов объекта, а не для дочерних элементов?
Почему весенние данные jpa сопоставляют ассоциацию «один к одному» с «один ко многим»
Hibernate — ленивая выборка ассоциации @OneToOne с одним и тем же родителем, на который ссылаются несколько рекурсивно сопоставленных дочерних элементов
Ошибка: org.hibernate.HibernateException: найдены общие ссылки на коллекцию