Spring TransactionTemplate присоединяется к транзакции неизвестного происхожденияJAVA

Программисты JAVA общаются здесь
Anonymous
Spring TransactionTemplate присоединяется к транзакции неизвестного происхождения

Сообщение Anonymous »

Код: Выделить всё

'org.springframework.boot' version '3.3.13'
У меня есть простая структура задач.

Код: Выделить всё

public class TaskRunner implements DelayedTaskRunner {
private static final String TASK_WORKER_THREAD_NAME_PATTERN = "Task-Worker-%d";

private TaskExecutor taskExecutor;

private ThreadPoolExecutor runnerThreadPool;

public TaskRunner(
TaskExecutor taskExecutor,
Integer defaultThreadPoolSize,
Integer maximumThreadPoolSize,
Duration keepExtraThreadsAliveForSeconds
) {
this.taskExecutor = taskExecutor;
this.runnerThreadPool = new ThreadPoolExecutor(
defaultThreadPoolSize,
maximumThreadPoolSize,
keepExtraThreadsAliveForSeconds.toMillis(),
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue(100),
new ThreadFactoryBuilder().setNameFormat(TASK_WORKER_THREAD_NAME_PATTERN).build()
);
}

public TaskInitiationResult runWorker() {

try {
Future taskRef = runnerThreadPool.submit(this::executeTask);
return new TaskInitiationResult(taskRef);
} catch (RejectedExecutionException e) {
return new TaskInitiationResult(null);
}
}

private void executeTask() {
try {
taskExecutor.executeNextTask();
} catch (Exception e) {
log.error("Error while executing Task", e);
}
}

public void shutdown() {
ExecutorServiceManagementUtil.shutdown(runnerThreadPool, log);
}

@Override
public String getAssignedTaskScope() {
return "TASK_SCOPE_NAME";
}
}
TaskRunner.java — это простой контейнер ThreadPool. Внешний цикл while постоянно запускает метод runWorker, который просто делегирует вызов исполнителя потоку. Исполнитель тоже прост:

Код: Выделить всё

public class TheTaskExecutor implements TaskExecutor {
private TaskWorkerReportCollector workerReportCollector;
private TaskRepository taskRepository;
private TransactionTemplate transactionTemplate;
private Duration sleepOnWorkNotFound;
private CommandBus commandBus;

private Integer amountOfTasksToSelect;

public TheTaskExecutor(
CommandBus commandBus,
TaskWorkerReportCollector workerReportCollector,
TaskRepository taskRepository,
TransactionTemplate transactionTemplate,
Duration sleepOnWorkNotFound,
Integer amountOfTasksToSelect
) {
this.commandBus = commandBus;
this.amountOfTasksToSelect = amountOfTasksToSelect;
this.taskRepository = taskRepository;
this.transactionTemplate = transactionTemplate;
this.sleepOnWorkNotFound = sleepOnWorkNotFound;
this.workerReportCollector = workerReportCollector;
}

public void executeNextTask() {
long threadId = Thread.currentThread().threadId();

Instant resumeWorkTimestamp = workerReportCollector.getResumeWorkTimestamps().get(threadId);
if (resumeWorkTimestamp != null && resumeWorkTimestamp.isAfter(Instant.now())) {
return;
}

transactionTemplate.executeWithoutResult(transactionStatus -> {
List tasks = taskRepository.deleteWithSelectNextTasksToExecute(amountOfTasksToSelect, Instant.now());
if (tasks.isEmpty()) {
workerReportCollector.put(threadId, Instant.now().plusMillis(sleepOnWorkNotFound.toMillis()));
return;
}

workerReportCollector.evict(threadId);

for (DelayedTask task : tasks) {
try {
commandBus.execute(task.getCommand());
} catch (Exception e) {
throw e;
}
}
});
}
}
С некоторой защитой от отсрочки (

Код: Выделить всё

workerReportCollector
 – это простая карта), она использует транзакцииTemplate.executeWithoutResult для запуска новой транзакции. Вот в чем проблема: каким-то образом эта Задача присоединяется к Транзакции, а не создает собственную. Этот вывод сделан на основе вывода pg_stat_activity (не могу поделиться), в котором транзакция длилась 4 часа, и после того, как был выпущен pg_terminate_backed, имя потока, появившееся в трассировке стека исключений, относилось к потоку бегуна.
Поэтому я ищу общий ответ на вопрос: где поток в полностью изолированном пуле может получить соединение с активной транзакцией? Означает ли это, что Соединение с активной транзакцией остается в пуле Хикари?

Вернуться в «JAVA»