We have a Spring application, I want to add a service that will handle 10Ks IDs with multiple threads but will be as background process without impact production realtim
Here there is a nice tutorial about priority based task execution in Spring. Maybe this may help you in some ways.
This is a method of creating a configurable ¨heap¨ of task and always keep your main task in the top of the heap.
To sum up this process you should create a custom Task Executor. Firstly you need to create a ThreadPoolTaskExecutor bean with one method being overidden. The properties that should be modified are: CorePoolSize(initial number of threads), QueueCapacity(the number of threads waiting in the queue), and MaxPoolSize(maximum number of threads). With these parameters you can configure your applications limitations in order for this service not to impact the production performance.
@Bean("CustomTaskExecutor")
public TaskExecutor threadPoolTaskExecutor(
@Value("${spring.async.core-pool-size}") int corePoolSize,
@Value("${spring.async.max-pool-size}") int maxPoolSize,
@Value("${spring.async.queue-capacity}") int queueCapacity) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() {
@Override
protected BlockingQueue createQueue(int queueCapacity) {
return new PriorityBlockingQueue(queueCapacity);
}
};
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
return executor;
}
After that,you need to make tasks with priorities that the task executor can understand. For that we would need to create two classes: 1) A custom class that implements Runnable interface that will be running the task 2) A wrapper class that extends FutureTask and implementsComparable interface, so that the task executor could understand the priority picking logic of the tasks
public class Task implements Runnable {
private Consumer jobConsumer;
private Job job;
public Job getJob() {
return this.job;
}
public Task(Consumer jobConsumer, Job job) {
this.jobConsumer = jobConsumer;
this.job = job;
}
@Override
public void run() {
this.jobConsumer.accept(job);
}
}
Then you have the FutureCustomTask class:
public class FutureCustomTask extends FutureTask implements Comparable {
private Task task;
public FutureCustomTask(Task task) {
super(task, null);
this.task = task;
}
@Override
public int compareTo(FutureCustomTask o) {
return task.getJob().getPriority().compareTo(o.task.getJob().getPriority());
}
}
For the execution the TaskExecutor needs to be Autowired. Then, you can create your Task object, wrap it inside FutureCustomTask, and pass it to TaskExecutor.The code should look like this:
@Autowired
private TaskExecutor taskExecutor;
@Autowired
private JobBusiness jobBusiness;
...
Task task = new Task(jobBusiness::performSomethingOn, job);
taskExecutor.execute(new FutureCustomTask(task));