Reputation: 2611
I have one spring boot controllers which recives many users like below
sample json
{
"users": [
{ "name":"john", "age":18, "type":"1"},
{ "name":"kim", , "age":18, "type":"2"},
{ "name":"Fits", "age":18, "type","3"},
]
}
request handler
@RequestMapping(value = "/users", method = RequestMethod.POST, headers = "Accept=application/json")
public void Add(@RequestBody List<user> users) throws Exception {
// Here I am iterating users and writing one by one to different message topic based on the type
// if any error in the given user while writing to message topic I am storing that user in other DB
}
it works well when I have some 100 users in the user list, but if list is big like 1000 etc it takes too much time. so is there any spring batch job where I can assign to that to perform this?
I just want to return http response code 202 to request and assign this payload to spring batch job
Upvotes: 3
Views: 3660
Reputation: 1518
https://github.com/softnrajkumar1994/multithreading-example
Important
1)Instead 1000 users in a single request please send those users list as small chunks
public class ThreadManager {
private static ThreadPoolExecutor stpe = null;
static {
/**
*
* corePoolSize --->the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
*
* maximumPoolSize --- >the maximum number of threads to allow in the
* pool
*
* keepAliveTime---> when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
*
* unit the time unit for the {@code keepAliveTime} argument
*
* workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
*/
stpe = new ThreadPoolExecutor(5, 10, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1090));
System.out.println("THREAD MANAGER INTIALIZED SUCCESSFULLY");
}
public static void execute(Runnable task) {
stpe.execute(task);
}
}
The above class will receive runnable task and executes with the idle threads of threadpool.
Sample User class:
public class User {
private String name;
private String mobile;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
@RestController
public class UserController {
@PostMapping("/users")
public void Add(@RequestBody List<User> users) throws Exception {
/**
* Here we are rotating user's list and assigning each and every user into a
* separate worker thread, so that work will be done parallely
*/
for (User user : users) {
try {
ThreadManager.execute(new UserWork(user));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Custom runnable worker class for working on user object.Do you business implementation in runnable method.
public class UserWork implements Runnable {
private User user;
public UserWork(User user) {
this.user = user;
}
@Override
public void run() {
// Please add your businees logic here
// Here I am iterating users and writing one by one to different message topic based on the type
// if any error in the given user while writing to message topic I am storing that user in other DB
}
}
Upvotes: 0
Reputation: 913
One option is to use Spring Async Task
for long running processes in separate thread, hence wouldn't wait to execute whole request and send response back.
First configure Async task like this.
@Configuration
@EnableAsync
public class AsynchTaskConfiguration{
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("ProcessUsers-");
executor.initialize();
return executor;
}
}
And Here you can use Async task in your service for processing users
@Service
public class UserProcessingService {
private final AnotherUserProcessingService service;
@Autowired
public UserProcessingService (AnotherUserProcessingService service) {
this.service= service;
}
@Async
public CompletableFuture<List<User>> processUser(List<User> users) throws InterruptedException {
users.forEach(user -> logger.info("Processing " + user));
List<User> usersListResult = service.process(users);
// Artificial delay of 1s for demonstration purposes
Thread.sleep(1000L);
return CompletableFuture.completedFuture(usersListResult);
}
}
processUser(User user)
is annotated with @Async
indicating the method will run in separate thread according to taskExecutor
configuration provided above. @EnableAsync
enable Spring
to run any method in background thread that is annotated with @Async
.
And make sure your service using async task to process users must be created inside a @Configuration
class or picked up by @ComponentScan
. You can customize your taskExecutor
according to your needs.
Here you can find How ThreadPoolTaskExecutor works.
Upvotes: 4