2

Giving the following code which takes a request with a web shop order as JSON in Spring Boot. The order should be handed over to the method processJsonOrder on which the order will be processed. After handing over, the web service should return OK to the client. Processing in processJsonOrder should be async without blocking the return to the client.

@RestController
public class WebShopOrderController {

    @Autowired
    private OrderService orderService;

    @PostMapping(value = "/wc-order")
    public void getWcOrder(@RequestBody String jsonOrder, @RequestHeader Map<String, String> headers) {
        log.info("order received");
    
        // should be done async
        processJsonOrder(jsonOrder);

        return;
    }
}

However, jsonOrder processed in processJsonOrder should be processed one by one. Maybe by a queue, or there is a nice solution in Spring to do so. The idea is that jsonOrders are waiting when an order is executed within processJsonOrder. Currently, when two order updated arrive within seconds, order will be inserted into the database by processJsonOrder twice, as the thread processing the jsonOrder has not reached the commit point yet. There is some code in the orderService to check for duplicates on database level, but that doesn't help always.

The OrderService.java

@Service
public class OrderService {
    
    @Async
    @Transactional
    public void processJsonOrder(WoocommerceOrder wcOrder) {
        // performing business logic
    }

}

I expect that there is an elegant solution for that, or maybe doing the processJson order Async is the wrong approach. Important is that the calling client gets back an answer immediately, but the order is processed afterwards asynchronously, but one by one.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Fabo137
  • 46
  • 4
  • Does this answer your question? [Spring @Async limit number of threads](https://stackoverflow.com/questions/13206792/spring-async-limit-number-of-threads) – Pino Apr 11 '23 at 16:58

1 Answers1

0

What you're trying to do with your code is called reach a mutual exclusion to avoid a race condition - two or more processes or threads simultaneously reach a critical segment of your code and try to read and/or update the same piece of data, potentially causing a bug or error. In java , there is a built in feature to avoid this kind of problem: The synchronized keyword.

First, on your Controller, configure the Thread(s):

@RestController
public class WebShopOrderController {

    @Autowired
    private OrderService orderService;

    @PostMapping(value = "/wc-order")
    public void getWcOrder(@RequestBody String jsonOrder, @RequestHeader Map<String, String> headers) {
        log.info("order received");

        // Will be done async
        new Thread(() -> processJsonOrder(jsonOrder)).start();

        return;
    }
}

Then, just use the synchronized keyword on your @Service method:

@Service
public class OrderService {
    
    @Transactional
    public synchronized void processJsonOrder(WoocommerceOrder wcOrder) {
        // Only one Thread at a time will be allowed to enter this area.
        // performing business logic
    }

}