I am writing an application that periodically pull new rows (row.status == 'NEW') from a database table, do some processing on each row as JPA entity, then save the row back to the database with status == 'PROCESSED'.
DB table:
ID | Status
1 | PROCESSED
2 | NEW
3 | NEW
Java code: (Using Spring boot framework)
@Component
public class Processor {
// an JPA repository for selecting Items
@Autowired
ItemRepository itemRepository;
// a thread executor for submitting
ExecutorService executor = Executors.newSingleThreadExecutor();
@Scheduled(fixed-rate=1000)
void process() {
List<Item> newItems = itemRepository.findByStatus('NEW');
for(Item item : newItems) {
// process each item asyncronously
executor.submit(()-> {
// do some processing on this item and update status.
// THis is time consuming process, may take 4 or 5 seconds
item.setStatus("PROCESSED");
itemRepository.save(item);
});
}
}
}
The problem is, when one item item1 is still being processed in the executor, and have not be updated with status to PROCESSED, in next round of processing, it is still going to be selected by itemRepository.findByStatus('NEW'). And it will be submitted for processing again.
How to avoid such case from happening? (apart from changing fixed-rate to fixed-delay) Is there some kind of locking mechanism such as syncronize (item) { .... } such that once a database row is still in processing, it is not selected again in next round of process() method?