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?