Race condition when use Kafka and JPA

Viewed 430

I have a problem when using microservice and Kafka for example, I have Service A and Service B they communicate by Kafka and they share the same database inside the database and I have two entities A and B and they share a one-to-many relationship, when I update entity A in service A entity B gets updated/changed as wanted but when I view service B. I can't see the changes that happened in service A.

In my case example code :

here we are in service A:

KafkaService:

    public synchronized void getDriverService(Long orderId, Double longitude, Double latitude) {
    driverService.getDriver(orderId,longitude,latitude);
    driverService.collectionOrder(orderId);

}

driverService:

public void getDriver(Long orderId, Double longitude, Double latitude) {
    final Driver [] y={new Driver()};
    ascOrderRepository.findById(orderId).ifPresentOrElse(x->{
        List<DriverDTO> drivers = findAllCarNearMe(latitude, longitude);
        if(drivers.isEmpty())
            throwEmptyDriver();

        AscOrderDTO orderDto = ascOrderMapper.toDto(x);
        int check;
        for (DriverDTO dr : drivers) {
            check = checkDriver();
            if (check < 8) {
                log.debug("///////////////////////// driver accept" + dr.getId().toString());
                dr.setStatus(UNAVAILABLE);
                dr.updateTotalTrip();
                Driver driver=driverMapper.toEntity(dr);
                driver.addOrders(x);
                y[0]=driverRepository.save(driver);
                log.debug(dr.toString());
                log.debug("/////////////////////////////////////driver accept here /////////////////////////////////////////");
                break;
            }
        }
    },this::throwOrder);

}

// find All Car near me
public List<DriverDTO> findAllCarNearMe(Double latitude, Double longitude) {
    checkDistance(latitude,longitude);
    Point point = createPoint(latitude, longitude);
    List<Driver> driver = driverRepository.findNearById(point, 10);
    return driverMapper.toDto(driver);

}


public void collectionOrder(Long orderId)
{
    ascOrderRepository.findById(orderId).ifPresentOrElse(y->{

        if(y.getDriver()!=null) { // here new updated and find this updated into service A
            try {
                driverProducer.driverCollectionOrder(y.getId());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        else
        {
            throwDriverNotFind();
        }

    },this::throwOrder);

}

This is Producer:

     @Component public class DriverProducer { 
    public
  DriverProducer(KafkaTemplate<String, String> kafkaTemplate)   {
            this.kafkaTemplate = kafkaTemplate;     }
     
            public void driverCollectionOrder(Long orderId) throws Exception{           ObjectMapper obj=new ObjectMapper();
                kafkaTemplate.send("collecting",obj.writeValueAsString(orderId));
     
        }

Service B:

This is Consumer:

@KafkaListener(topics = "collecting",groupId= groupId)
public void doneOrderStatus(String data) throws NumberFormatException, Exception {
    try
    {
        log.debug("i am in done order status order consumer");

        OrderEvent event=OrderEvent.TO_BE_COLLECTED;
        orderService.changeStatus(event, Long.parseLong(data));
    }
    catch (Exception e)
    {
        throw new Exception(e.getMessage());
    }
}

This Method Has my Error:

    public void changeStatus(OrderEvent event, Long orderId) throws Exception {
    try {
        Optional<AscOrder> order=ascOrderRepository.findById(orderId);
        if (!order.isPresent()) {
            throw new BadRequestAlertException("cannot find Order", "Order entity", "Id invalid");
        }

        if(order.get().getDriver()!=null) { // cant find Change Here
            log.debug("===============================================================================================");
            log.debug(order.get().getDriver().toString());
            log.debug("===============================================================================================");
        }
        log.debug("i am in changeStatus ");
        stateMachineHandler.stateMachine(event, orderId);
        stateMachineHandler.handling(orderId);

    } catch (Exception e) {
        throw new Exception(e.getMessage());
    }
}
1 Answers

The problem may be about the separate ORM sessions held by the services. To overcome this you may try to reload the entity. To do that,

1- wire the entity manager

@Autowired
EntityManager entityManager;

2- Decorate changeStatus function with @Transactional annotation, unless there is an active transaction already going on.

3- Refresh the order entity

entityManager.refresh(order)
Related