Spring Boot处理大请求主体-通过多线程处理批量

时间:2019-06-18 17:04:54

标签: spring spring-boot spring-batch batch-processing

我有一个spring boot控制器,可以像下面的一样吸引许多用户

样本json

system("cmd /c .$targetBAT");

<?php
if(isset($_POST['run']))
{

echo $_SESSION["runPath"];
$filename = '\UXAutomation\UXAutomation.bat';
$targetBAT = $_SESSION["runPath"].$filename;

if (file_exists($targetBAT)) {
echo "RESULT:OK";
echo $targetBAT;
system("cmd /c .$targetBAT");
} else {
echo "RESULT:KO";
}
 } 
 ?>

请求处理程序

{
  "users": [
    { "name":"john", "age":18, "type":"1"},
    { "name":"kim", , "age":18, "type":"2"},
    { "name":"Fits", "age":18, "type","3"},
  ]
 }

当我的用户列表中有大约100个用户时,它工作得很好,但是如果列表很大(如1000个),则需要太多时间。 所以我可以在其中分配任何春季批处理工作来执行此操作吗?

我只想返回http响应代码202来请求并将此有效负载分配给spring批处理作业

2 个答案:

答案 0 :(得分:1)

一种选择是将Spring Async Task用于长时间运行于单独线程中的进程,因此,您将等不及执行整个请求并将响应发送回去。

首先像这样配置异步任务。

@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;
    }
}

在这里,您可以在服务中使用异步任务来处理用户

@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)带有@Async注释,指示该方法将根据上面提供的taskExecutor配置在单独的线程中运行。 @EnableAsync使Spring能够在带有@Async注释的后台线程中运行任何方法。 并确保您使用异步任务处理用户的服务必须在@Configuration类内部创建或由@ComponentScan获取。您可以根据需要自定义taskExecutor

在这里您可以找到ThreadPoolTaskExecutor的工作方式。

答案 1 :(得分:0)

https://github.com/softnrajkumar1994/multithreading-example

重要

1)而不是在单个请求中有1000个用户,请以小块形式发送这些用户列表

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);
    }
}

上面的类将接收可运行的任务,并使用线程池的空闲线程执行。

示例用户类别:

 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();
            }
        }
    }

}

用于处理用户对象的自定义可运行工作者类。您是否使用可运行方法进行业务实现。

  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
    }

}