Spring background MVC process

I come from the Perl background and write my first Java MVC web application using Spring.

My webapp allows users to submit orders that the application processes synchronously, invoking a third-party SOAP service. The next stage of the project is to allow users to send bulk orders (for example, CSVs containing 500 lines) and process them asynchronously. Here is a snippet of my existing controller:

@Controller @Service @RequestMapping(value = "/orders") public class OrderController { @Autowired OrderService orderService; @RequestMapping(value="/new", method = RequestMethod.POST) public String processNewOrder(@ModelAttribute("order") Order order, Map<String, Object> map) { OrderStatus orderStatus = orderService.processNewOrder(order); map.put("orderStatus", orderStatus); return "new"; } } 

I plan to create a new @RequestMapping to work with incoming CSV and modify the OrderService to be able to split the CSV and save individual orders in the database.

My question is: what is the best approach to creating background workers in an MVC Spring application? Ideally, I would have 5 threads processing these orders and, most likely, from the queue. I read about @Async or posted a Runnable in a SimpleAsyncTaskExecutor bean, and I'm not sure where to go. Some examples will really help me.

+6
source share
2 answers

I think Spring Batch is overkill, not what you are looking for. This is more for batch processing, like writing all orders to a file, and then processing all at once, whereas it looks like asynchronous processing, where you just want to have a work queue and process it that way.

If this is true, I would consider using a pub / submodel using JMS. There are several JMS providers, such as Apache ActiveMQ or Pivotal RabitMQ. Essentially, your OrderService would break the CSV into units of work, push them to the JMS queue, and you would have a few Consumer settings to read from the queue and complete the work task. There are many ways to tune this, but I would just make a class to hold worker threads and tune the number of threads. Other additional benefits are here:

  • You can screen the user code and even run it on completely different hardware if you want.
  • MQ is a fairly well-known process, and there are many commercial offers. This means that you can easily write your order processing system in C # using MQ to move messages, or even use the Spring Package if you want. Heck, there is even an MQ series for the host, so you could process your order on the mainframe in COBOL if you liked it.
  • It's stupid to just add more consumers or manufacturers. Just subscribe to the Queue and they will leave!
  • Depending on the product used, the queue maintains state, so messages are not "lost". If all users are disconnected, the queue will simply back up and save messages until consumers return.
  • Queues are also usually more reliable. The producer can come down, and you won’t even flinch consumers. Consumers can go down, and the manufacturer does not even need to know.

However, there are some disadvantages. You now have an additional error. You probably want to control the depth of the queue, and you will need to provide enough space to store messages when caching messages. In addition, if processing time can be a problem, you may need to monitor how quickly the queues in the queue are processed to make sure that it does not copy too much or violates any SLA that might be in place.

Edit: Add an example ... If I had a streaming class, for example:

 public class MyWorkerThread implements Runnable { private boolean run = true; public void run() { while (run) { // Do work here... } // Do any thread cooldown procedures here, like stop listening to the Queue. } public void setRunning(boolean runState) { run = runState; } } 

Then I would start creating threads using a class like this:

 @Service("MyThreadManagerService") public class MyThreadManagerServiceImpl implements MyThreadManagerService { private Thread[] workers; private int workerPoolSize = 5; /** * This gets ran after any constructors and setters, but before anything else */ @PostConstruct private void init() { workers = new Thread[workerPoolSize]; for (int i=0; i < workerPoolSize; i++) { workers[i] = new Thread(new MyWorkerThread()); // however you build your worker threads workers[i].start(); } } /** * This gets ran just before the class is destroyed. You could use this to * shut down the threads */ @PreDestroy public void dismantle() { // Tell each worker to stop for (Thread worker : workers) { worker.setRunning(false); } // Now join with each thread to make sure we give them time to stop gracefully for (Thread worker : workers) { worker.join(); // May want to use the one that allows a millis for a timeout } } /** * Sets the size of the worker pool. */ public void setWorkerPoolSize(int newSize) { workerPoolSize = newSize; } } 

Now you have a good class of service that you can add to track, restart, stop, etc. all your workflows. I did this @Service because it felt more right than a simple @Component , but technically it could be anything as long as Spring knows how to pick it up when you perform auto-installation. The init() method in the service class is what starts the threads, and dismantle() used to gracefully terminate them and wait for them to complete. They use the @PostConstruct and @PreDestroy , so you can name them whatever you want. You probably have a constructor on MyWorkerThread for setting up queues, etc. Also, as a disclaimer, all of this was written from memory, so there may be some minor compilation issues or method names may be slightly disabled.

There may be classes that are already available for this kind of thing, but I have never seen them myself. Does anyone know of a better way to use the finished parts that I would like to get more educated.

+1
source

If your order size can grow in the future, and you want a scalable solution, I suggest you upgrade to the Spring-Batch framework . It is very easy for me to integrate with spring-mvc and with a minimal configuration, you can easily achieve a very reliable parallel processing architecture. Use the Spring -batch separation . Hope this helps you! Feel free to ask if you need help integrating with Spring MVC.

0
source

Source: https://habr.com/ru/post/972572/


All Articles