Método Async - java spring

Fiz o um serviço @Async(“taskExecutor”), ai ele entra no serviço. Até ai tudo. bem;

@Transactional
	@Async("taskExecutor")
	void run(PdfReader pdfReader, Usuario usuarioLogado, byte[] bytes, String contentType, String nomeArquivo, long tamanhoArquivo) {

metodo

}

Com arquivo pequenos, o procedimento é rapido e eu consigo navegar em outras telas. Mas se aarquivo tem por exemplo 1 Mb. O processo acaba. Mas se eu entro em outra página o sistema trava.

Ele não deveria ficar em outro processo ?

Em teoria deveria, como estão as suas configurações do async?

Eu geralmente configuro da seguinte forma:

Crio uma classe que implementa o TaskDecorator (Ela é responsável por tratar separadamente os contextos de cada thread):

public class MdcTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable runnable) {
        var requestAttributes = RequestContextHolder.currentRequestAttributes();
        var contextMap = MDC.getCopyOfContextMap();

        return () -> {
            try {
                RequestContextHolder.setRequestAttributes(requestAttributes);
                MDC.setContextMap(contextMap);
                runnable.run();
            } finally {
                MDC.clear();
                RequestContextHolder.resetRequestAttributes();
            }
        };
    }

}

Configuro uma classe para habilitar o uso do async criando um pool de thread’s:

@EnableAsync
@Configuration
public class AsyncConfiguration {

    @Bean
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setTaskDecorator(new MdcTaskDecorator());
        executor.setThreadNamePrefix("asyncPoolExecutor-");
        executor.initialize();
        return executor;
    }

}

Depois só chamo em qualquer método:

@Async
public void processAsync() {
    ...
}

Está assim:

package br.com.ghnetsoft.takeprofit.config;

import java.util.concurrent.Executor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor;

@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {

	private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);

	private final TaskExecutionProperties taskExecutionProperties;

	public AsyncConfiguration(TaskExecutionProperties taskExecutionProperties) {
		this.taskExecutionProperties = taskExecutionProperties;
	}

	@Override
	@Bean(name = "taskExecutor")
	public Executor getAsyncExecutor() {
		log.debug("Creating Async Task Executor");
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(taskExecutionProperties.getPool().getCoreSize());
		executor.setMaxPoolSize(taskExecutionProperties.getPool().getMaxSize());
		executor.setQueueCapacity(taskExecutionProperties.getPool().getQueueCapacity());
		executor.setThreadNamePrefix(taskExecutionProperties.getThreadNamePrefix());
		return new ExceptionHandlingAsyncTaskExecutor(executor);
	}

	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return new SimpleAsyncUncaughtExceptionHandler();
	}
}

Tenta configurar um TaskDecorador no bean do seu Executor e veja se muda o comportamento.

Fiz assim:

package br.com.ghnetsoft.takeprofit.config;

import java.util.concurrent.Executor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
public class AsyncConfiguration {

	@Bean
	public Executor asyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setTaskDecorator(new MdcTaskDecorator());
		executor.setThreadNamePrefix("asyncPoolExecutor-");
		executor.initialize();
		return executor;
	}
}

e

package br.com.ghnetsoft.takeprofit.config;

import java.util.Map;

import org.slf4j.MDC;
import org.springframework.core.task.TaskDecorator;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

public class MdcTaskDecorator implements TaskDecorator {

	@Override
	public Runnable decorate(Runnable runnable) {
		RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
		Map<String, String> contextMap = MDC.getCopyOfContextMap();
		return () -> {
			try {
				RequestContextHolder.setRequestAttributes(requestAttributes);
				MDC.setContextMap(contextMap);
				runnable.run();
			} finally {
				MDC.clear();
				RequestContextHolder.resetRequestAttributes();
			}
		};
	}
}

e

@Transactional
	@Async
	public void run(PdfReader pdfReader, Usuario usuarioLogado, byte[] bytes, String contentType, String nomeArquivo,
			long tamanhoArquivo) {

}

Deu este erro:

Exception in thread "asyncPoolExecutor-1" java.lang.NullPointerException
	at java.util.HashMap.putMapEntries(Unknown Source)
	at java.util.HashMap.putAll(Unknown Source)
	at java.util.Collections$SynchronizedMap.putAll(Unknown Source)
	at ch.qos.logback.classic.util.LogbackMDCAdapter.setContextMap(LogbackMDCAdapter.java:197)
	at org.slf4j.MDC.setContextMap(MDC.java:264)
	at br.com.ghnetsoft.takeprofit.config.MdcTaskDecorator.lambda$0(MdcTaskDecorator.java:19)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)

Provavelmente é porquê você não está manipulando os contextos, mas isso não chega a ser algo essencial, remove ele do seu TaskDecorator!

Exemplo:

public class MdcTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable runnable) {
        return () -> {
            try {
                runnable.run();
            } catch (Exception ex) {
                throw ex;
            }
        };
    }

}
1 curtida

fica preso do mesmo jeito

Ele trava é só inicia um outro processo, quando o primeiro termina. Isso não poderia acontecer.

Muito estranho, deve ter alguma coisa impactando nisso ainda :confused: