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
Related
I've defined 3 jobs using fixedDelayString=300000 (5 minutes) and I did that 3 these jobs will be executed independently. For that reason, I created an Async implementation. At first, each job worked fine, but in the time they started to delay a lot.
Each execution is about 5seg, but the next execution started to run after 10minutes. And occasionally 15 or 18minutes.
An example could be:
#EnableScheduling
public class AppConfig {
#Async('threadPoolTaskExecutor')
#Scheduled(fixedDelayString=15000)
public void doSomething1() {
// something that should run periodically
}
#Async('threadPoolTaskExecutor')
#Scheduled(fixedDelayString=300000)
public void doSomething2() {
// something that should run periodically
}
#Async('threadPoolTaskExecutor')
#Scheduled(fixedDelayString=300000)
public void doSomething3() {
// this job begins to have interval larger in each execution
}
}
#Configuration
#EnableAsync
public class AsyncConf {
#Bean("threadPoolTaskExecutor")
public TaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(1000);
executor.setThreadNamePrefix("Async-");
return executor;
}
}
ยดยดยด
To mention the fixed delay, it should be fixedDelay instead of fixedDelayString. Check below code:
#Async('threadPoolTaskExecutor')
#Scheduled(fixedDelay = 300000)
public void doSomething3() { ... }
Also you should write #EnableScheduling annotation on your configuration class.
Also note that fixedDelay specifies that job should run next after specified amount of time once execution is completed. If you want to run your jobs at fixed intervals, you should try fixedRate instead of fixedDelay. Check more about scheduling here - https://www.baeldung.com/spring-scheduled-tasks
I am scheduling the spring scheduler with SchedulingConfigurer as follows. However, new traceid is not getting created every time the "ProcessJob" method is getting called.
Even following method always logs with the same traceid.
log.info("Performing task");
What is the issue here? and how do i ensure new traceid everytime this job is triggered.
I have even tried wrapping "processJob" method call inside newSpan as follows: but no luck.
Fix 1: not working:
private void setSchedule() {
future =
taskScheduler.schedule(
() -> {
Span newSpan = tracer.nextSpan().name("newSpan").start();
try (SpanInScope ws = tracer.withSpanInScope(newSpan.start())) {
log.info("Performing task");
taskManager.processJob();
} finally {
newSpan.finish();
}
},
dynamicTrigger);
}
Original class that needs fix:
public class SchedulerConfig
implements SchedulingConfigurer, ApplicationListener<RefreshScopeRefreshedEvent> {
private final DynamicTrigger dynamicTrigger;
private final TaskManager taskManager;
private TaskScheduler taskScheduler;
private ScheduledFuture<?> future;
#Bean(destroyMethod = "shutdown")
public ExecutorService taskExecutor() {
return Executors.newScheduledThreadPool(1);
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
taskScheduler = taskRegistrar.getScheduler();
setSchedule();
}
private void setSchedule() {
future =
taskScheduler.schedule(
() -> {z
log.info("Performing task");
taskManager.processJob();
},
dynamicTrigger);
}
#Override
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
log.info("Rescheduling due to change in cron expression");
future.cancel(false);
setSchedule();
}
The way you start the span is not how you suppose to do it (e.g.: you call start twice). Please check the docs to see how to do it properly: https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/htmlsingle/#using-creating-and-ending-spans
The easiest way to start a new span is using #NewSpan on a method that belongs to a Spring Bean, please see the docs: https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/htmlsingle/#using-annotations-new-spans
For scheduling, I think it is way simpler using #Scheduled, see the docs: https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/htmlsingle/#sleuth-async-scheduled-integration
This is also instrumented out of the box by Sleuth so you don't need to do anything to start a new Span:
#Scheduled(fixedDelay = 1_000)
public void scheduled() {
log.info("Hey, look what I'm doing");
}
If you don't want to use #Scheduled, you can use a TraceableScheduledExecutorService as your ExecutorService, docs: https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/htmlsingle/#sleuth-async-executor-service-integration
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..
I need to do onething that I don't know wich is the best practice to this.
After I send one request to an especific service, this one returns OK and queue my request. I have a callback service that is used to notify when it ends.
The problem is that the whole process can take a long time and over without notify anything and after that I need to consider a timeout.
The application is SpringBoot APP and I was considering to use the annotations #EnableAsync and #Async on a service method with a Sleep time.
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("TIMCLL-");
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// TODO Auto-generated method stub
return null;
}
}
.
.
.
#Async
public void verifyStatusTimPayment() throws InterruptedException {
Thread.sleep(5000);
logger.info( "Executed after 5s " + new SimpleDateFormat("dd/MM/yyyy hh:mm:ss").format(new Date()));
}
The verification needs to be done 15 minutes after the request and have to occur just one time per request.
How can I do this without make a Thread.sleep ?????
You could use the ScheduledExecutorService to schedule the Task
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
...
scheduler.schedule(() -> {yourtaskhere}, 15, TimeUnit.MINUTES);
But this is not what you want. What if the server dies between the scheduling of the task and its execution? you will lose your task.
It would be better if you persist the message in a queue, and retrieve it later, or use any scheduler that uses persistence (a la Quartz)
you can add #EnableScheduling annotation to your configuration:
#Configuration
#EnableAsync
#EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("TIMCLL-");
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// TODO Auto-generated method stub
return null;
}
}
if you want to do schedule once and delayed you can call the taskScheduler :
#Autowired
private TaskScheduler taskScheduler;
and execute the task:
taskScheduler.schedule(
() -> {//your task},
//Your Delay task
);
i think we can use #Scheduled in latest spring. it will run every 15 minutes
like method is annotated as below
#Scheduled(cron = "0 0/15 * * * *")
public void verifyStatusTimPayment() throws InterruptedException {
logger.info( "Executed after 5s " + new SimpleDateFormat("dd/MM/yyyy hh:mm:ss").format(new Date()));
}
i know i am late but might help someone who is going through thread
You can use Redis backed delayed scheduler, which would guarantee you wouldn't lose your tasks. This can be done using Rqueue very easily.
In Rqueue you can enqueue a task which would run after 15 minutes as
public class Verification {
private String id;
}
#Component
class VerificationListener {
#RqueueListener(
value = "verification-queue")
public void onMessage(Verification verification) {
// do verification
}
}
#Service
class DelayedTaskService {
#Autowired private RqueueMessageSender rqueueMessageSender
public void enqeueVerification(Verification verification) {
rqueueMessageSender.enqueuIn("verification-queue", verification, Duration.ofMinutes(15);
}
}
P.S. I'm a developer of the Rqueue library.