I'm trying to copy Spring context to Runnable/Callable tasks for a special case. I want other threads to run as they run before.
I've read this How to enable request scope in async task executor
and implemented a custom ThreadPoolTaskExecutor + decorator.
#Configuration
public class ContextCopyConfig {
private Integer connectionsLimit=10;
#Bean(name = "contextExecutor")
public Executor contextExecutor() {
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setTaskDecorator(new ContextCopyingDecorator());
poolExecutor.setMaxPoolSize(connectionsLimit);
poolExecutor.setCorePoolSize(connectionsLimit);
poolExecutor.initialize();
return poolExecutor;
}
}
I was planning to use this executor as follows:
#Autowired
#Qualifier(value = "contextExecutor")
private Executor contextExecutor;
public void parallelHere() throws IOException, InterruptedException, ExecutionException {
Collection<Callable<Pair<String, OutputStream>>> tasks = new ArrayList<>(); //some tasks
//ExecutorService executor = Executors.newFixedThreadPool(connectionsLimit);
List<Future<Pair<String, OutputStream>>> results = ((ThreadPoolTaskExecutor) contextExecutor).getThreadPoolExecutor().invokeAll(tasks);
((ThreadPoolTaskExecutor) contextExecutor).getThreadPoolExecutor().shutdown(); //always reclaim resources
}
However, contextExecutor is always invoked (in any thread!).
How can I fix it?
This post:
How to create additional TaskExecutor beside TaskExecutionAutoConfiguration?
describes the issue. Springboot creates a default Executor only if user did not create a custom one.
In SpringBoot 2+ you have to use
#AutoConfigureAfter(TaskExecutionAutoConfiguration.class)
on your custom configuration.
In previous Spring versions however, no TaskExecutionAutoConfiguration exists and Executor is created by a factory. Using lines below, you can create the exect copy of default executor, created by Spring.
#Primary
#Bean
//see package org.springframework.aop.interceptor.AsyncExecutionInterceptor
public Executor getDefaultExecutor(){
// Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
// return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
return new SimpleAsyncTaskExecutor();
}
Related
I am trying to create a few instances of state machine from one uml-model. I use stateMachineFactory. I would like these machines working independently and asynchrously.
Everything work great if I use only "base" states. Machine instances can independently go to stateB and StateC. However, when I use regions and sub-states (stateD), machine instances execute action (insideStateD1) one after another. Please look at .
I've found that states are executed via stateMachineTaskExecutor (which default is SyncTaskExecutor) but substates are executed via taskScheduler (which default is ConcurrentTaskScheduler).
This is configuration:
#Configuration
#EnableStateMachineFactory
public class StateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
#Autowired
StateMachineComponentResolver<String, String> stateMachineComponentResolver;
#Bean
public StateMachineModelFactory<String, String> modelFactory() {
UmlStateMachineModelFactory umlStateMachineModelFactory = new UmlStateMachineModelFactory("classpath:uml/testSM1.uml");
umlStateMachineModelFactory.setStateMachineComponentResolver(stateMachineComponentResolver);
return umlStateMachineModelFactory;
}
#Override
public void configure(StateMachineModelConfigurer<String, String> model) throws Exception {
model
.withModel()
.factory(modelFactory());
}
#Override
public void configure(StateMachineConfigurationConfigurer<String, String> config) throws Exception {
config
.withConfiguration()
// .taskExecutor() // I tried various taskExecutors
// .taskScheduler() // I tried various taskSchedulers
;
}
}
What is the correct way to achieve many instances of state machine from the same model?
Multiple instances of a SM can be obtained by the StateMachineFactory.
stateMachineFactory.getStateMachine(); //builds a new state machine
The configuration that you have created in StateMachineConfig applies to all SM instances.
Spring State Machine uses TaskExecutor for region executions (doesn't matter top level or nested regions) and by default it's synchronous. To achieve async execution you need to override the default task executor. This can be achieved in the configuration:
#Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
config
.withConfiguration()
//other configs
.taskExecutor(myAsyncTaskExecutor())
}
public TaskExecutor myAsyncTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
return taskExecutor;
}
or by declaring a bean:
#Bean(name = StateMachineSystemConstants.TASK_EXECUTOR_BEAN_NAME)
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
return taskExecutor;
}
TaskScheduler is used for action executions (actions associated with states or transitions) and not for sub-states.
I create scheduler:
#Bean
TaskScheduler taskScheduler(){
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
threadPoolTaskScheduler.setThreadNamePrefix("Test-");
return threadPoolTaskScheduler;
}
I wait next:
Each 1 second triggered my scheduled method and start 5 threads(PoolSize(5)) and each thread will make my logic. For that I create scheduled method in #Component bean:
#Slf4j
#Component
public class MyScheduler {
private final TaskScheduler taskScheduler;
public MyScheduler(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
#Scheduled(fixedDelay = 1000L)
public void test(){
taskScheduler.schedule(() -> {
try {
Thread.sleep(9000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("test");
}, new Date());
}
}
It work fine.
each 1 second start test() method and work 9 seconds. On 5 secon I have full threadPool and wait first free thread. If I set sleep(5000L) - threadPool can not fill up.
But now I need change poolSize in runtime. for example from 5 to 10. How can I do it?
According to the documentation you can resize the scheduler at runtime by calling setPoolSize() (see: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.html#setPoolSize-int-)
The problem is: you need to have a reference to the specific class ThreadPoolTaskScheduler instead of the interface TaskScheduler.
You need to decide if you want to change the references from TaskScheduler to ThreadPoolTaskScheduler without breaking anyhting in your code
I have a spring batch application with a series of jobs. I want to send an email after ALL the jobs have completed, but I'm not sure the best way to do this. The options I am considering are:
Run the jobs in a certain order, and amend the JobListener of the last job, so that it will send the email. Downside with this is it won't work if a further job is added to the end of the batch.
Add a new job which will send the email and order the jobs, making sure this additional job is run last.
Are there any built in spring-batch constructs that will be triggered on completion of the entire batch?
The final option would be my preferred solution, so my question is, are there any spring-batch classes that listen for batch completion (similar to JobExecutionListenerSupport or a Step Listener)?
No. I am not aware of any batch listener that listen for the whole batch's completion.
I have two alternatives for you. Both allows you to stick to Spring.
(1) If your application is designed as perpetual (i.e. like a web-server), you can inject a custom jobLauncher, grab the TaskExecutor and wait its completion (either through simple counters that counts call-backs from afterJob functions or through a certain amount of time that it requires all jobs to be submitted -- not necessarily started).
Add a configuration class like this:
#Configuration
class JobConfiguration implements InitializingBean {
TaskExecutor taskExecutor;
#Bean TaskExecutor taskExecutor () {
// here, change to your liking, in this example
// I put a SyncTaskExecutor
taskExecutor = new SyncTaskExecutor();
return taskExecutor;
}
#Bean
public JobLauncher jobLauncher(#Autowired JobRepository jobRepository,
#Autowired TaskExecutor taskExecutor) {
SimpleJobLauncher launcher = new SimpleJobLauncher();
launcher.setJobRepository(jobRepository);
launcher.setTaskExecutor(taskExecutor);
return launcher;
}
List<Job> jobs;
// I don't use this in this example
// however, jobs.size() will help you with the countdown latch
#Autowired public void setJobs (List<Job> jobs) {
this.jobs = jobs;
}
#AfterPropertiesSet
public void init () {
// either countdown until all jobs are submitted
// or sleep a finite amount of time
// in this example, I'll be lazy and just sleep
Thread.sleep(1 * 3600 * 1000L); // wait 1 hour
taskExecutor.shutdown();
try {
taskExecutor.awaitTermination();
} catch (Exception e) {}
finally {
// send your e-mail here.
}
}
}
(2) If your application stops when all jobs are done, you can simply follow this to send out an e-mail.
I repeat a few lines of code for completeness:
public class TerminateBean {
#PreDestroy
public void onDestroy() throws Exception {
// send out e-mail here
}
}
We also have to add a bean of this type:
#Configuration
public class ShutdownConfig {
#Bean
public TerminateBean getTerminateBean() {
return new TerminateBean();
}
}
If I understand correctly, you have a job of jobs. In this case, you can define an enclosing job with a series of steps of type JobStep (which delegates to a job). Then, you can register a JobExecutionListener on the enclosing job. This listener will be called once all steps (ie sub-jobs) have completed.
More details about the JobStep here: https://docs.spring.io/spring-batch/4.0.x/api/org/springframework/batch/core/step/job/JobStep.html
Can anybody tell my is there a way of using the Spring Framework's #Async annotation without blocking / waiting on the result? Here is some code to clarify my question:
#Service
public class AsyncServiceA {
#Autowired
private AsyncServiceB asyncServiceB;
#Async
public CompletableFuture<String> a() {
ThreadUtil.silentSleep(1000);
return asyncServiceB.b();
}
}
#Service
public class AsyncServiceB {
#Async
public CompletableFuture<String> b() {
ThreadUtil.silentSleep(1000);
return CompletableFuture.completedFuture("Yeah, I come from another thread.");
}
}
and the configuration:
#SpringBootApplication
#EnableAsync
public class Application implements AsyncConfigurer {
private static final Log LOG = LogFactory.getLog(Application.class);
private static final int THREAD_POOL_SIZE = 1;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
final AsyncServiceA bean = ctx.getBean(AsyncServiceA.class);
bean.a().whenComplete(LOG::info);
};
}
#Override
#Bean(destroyMethod = "shutdown")
public ThreadPoolTaskExecutor getAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(THREAD_POOL_SIZE);
executor.setMaxPoolSize(THREAD_POOL_SIZE);
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// omitted
}
}
When I run the application the executor goes through calling AsyncServiceA.a() and leaves, but it still holds the thread from the pool waiting on the CompletableFuture.get() method. Since there is just a single thread in the pool the AsyncServiceB.b() cannot be executed. What I'm expecting is that thread to be returned to the pool after it executes the AsyncServiceA.a() and then be available to execute the AsyncServiceB.b().
Is there a way to do that?
Note 1: I've tried with ListenableFuture also but the result is the same.
Note 2: I've successfully did it manually (without the #Async) by giving the executor to each method like so:
AsyncServiceA
public CompletableFuture<String> manualA(Executor executor) {
return CompletableFuture.runAsync(() -> {
LOG.info("manualA() working...");
ThreadUtil.silentSleep(1000);
}, executor)
.thenCompose(x -> asyncServiceB.manualB(executor));
}
AsyncServiceB
public CompletableFuture<String> manualB(Executor executor) {
return CompletableFuture.runAsync(() -> {
LOG.info("manualB() working...");
ThreadUtil.silentSleep(1000);
}, executor)
.thenCompose(x -> CompletableFuture
.supplyAsync(() -> "Yeah, I come from another thread.", executor));
}
Here is the ThreadUtil if someone was wondering.
public class ThreadUtil {
public static void silentSleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Update: Added issue for non-blocking Async annotation https://jira.spring.io/browse/SPR-15401
The #Async support has been part of Spring since Spring 3.0 which was way before the existence of Java8 (or 7 for that matter). Although support has been added for CompletableFutures in later versions it still is to be used for simple async execution of a method call. (The initial implementation reflects/shows the call).
For composing callbacks and operate non blocking the async support was never designed or intended to.
For non blocking support you would want to wait for Spring 5 with its reactive/non-blocking core, next to that you can always submit a ticket for non-blocking support in the async support.
I've responded on the ticket https://jira.spring.io/browse/SPR-15401 but I'll respond here as well to qualify the response by M. Deinum.
#Async by virtue of how it works (decorating the method call via AOP) can only do one thing, which is to turn the entire method from sync to async. That means the method has to be sync, not a mix of sync and async.
So ServiceA which does some sleeping and then delegates to the async ServiceB would have to wrap the sleeping part in some #Async ServiceC and then compose on ServiceB and C. That way ServiceA becomes async and does not need to have the #Async annotation itself..
This is my scenario:
My app has Mongo Auditing enabled, with a custom AuditorAware which gets the current user from the SecurityContext. This works well with synchronous methods, and the current auditor is successfully saved, but I can't make it work properly with #Async methods.
I have an async method (CompletableFuture) that makes some updates on my Mongo Database. When the AuditorAware.getCurrentAuditor() is called, no authentication info exists, and I can't get the current auditor (SecurityContextHolder.getContext().getAuthentication() returns null).
#Override
public User getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()
|| authentication instanceof AnonymousAuthenticationToken) {
log.error("Not authenticated");
return null;
}
[...]
}
I'm using a DelegatingSecurityContextAsyncTaskExecutor:
#Configuration
#EnableAsync
public class AsyncConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(200);
executor.initialize();
return new DelegatingSecurityContextAsyncTaskExecutor(executor);
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new ItacaExceptionHandler();
}
}
How can I make it work properly?
Spring security context is always bound to Threadlocal.
Probabably you may to additionally set MODE_INHERITABLETHREADLOCAL for the security context.
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
return methodInvokingFactoryBean;
}
http://www.ogrigas.eu/spring/2010/04/inherit-spring-security-context-in-child-threads
How to set up Spring Security SecurityContextHolder strategy?
Following the comments on kuhajeyan's answer, it appears you are not properly using CompletableFuture with Spring #Async.
If you launch your tasks by using e.g. CompletableFuture.supplyAsync(Supplier), they will be executed by the common ForkJoinPool and not the one you have configured for #Async. You could use the overloads that take an Executor as argument, but it would not actually benefit from the advantages of #Async.
What you should do, instead, is let Spring handle the task execution, and simply return a completed CompletableFuture like this:
#Async
public CompletableFuture<String> someMethod() {
// do some computation, but return a completed future
return CompletableFuture.completedFuture("Hello World!");
}
Spring will then execute your method asynchronously in the configured executor while immediately return a CompletableFuture which will be completed when your method returns.
If you are using Spring 4.2 or above, this is supported out of the box. Otherwise there is a bit of implementation required, but that would be for another question.