I have 2 instances of my Spring boot application, I am using spring JPA. Cron scheduler run method every one hour which first, check if record is already updated, if it's updated it should skip and don't update, but it's updated anyway on both instances. How to implement, something like synchronized, allow to read only when something is done?
@Scheduled(cron = "0 0 * * * ?", zone = "Europe/Paris")
public void updateServers() {
applicationServerRepository.findAll().forEach(this::updateServerInfo);
}
CodePudding user response:
Please explain the problem more detailed&exact. But as I understand, you should:
Or run the cron jobs only in one instance. (Back in 90ies we did it "manually", but spring-boot-profiles offer here great opportunity: decorate "all @scheduled beans" (re-factoring!?) with
@Profile("cronFooBar")
, and activate/add it only on one instance.)Or, if you also want cron jobs "load balanced", then you should find a way to synchronize/lock. (probably best in
updateServerInfo
orupdateServers
. (more details!? ..I am sure both instances will find "some object to lock on", at least the database (table, row, ..)))
As proposed by Erkan/found on internet, with "little setup" (and discarding quartz!), you can have a handy annotation for this, like:
@SchedulerLock(name = "...",
lockAtLeastForString = "...", lockAtMostForString = "...")
But I suppose, it is also possible with spring-data-jpa (only & quartz) resources, like:
Add (pessimistic) locking:
interface ApplicationServerRepository ... { @Lock(LockModeType.PESSIMISTIC_READ) @Query("select as from ApplicationService ...") findAllForCron(); ... }
Catch it:
@Scheduled(cron = "0 0 * * * ?", zone = "Europe/Paris") public void updateServers() { try { applicationServerRepository .findAllForCron() .forEach(this::updateServerInfo); } catch (javax.persistence.PessimisticLockException plex) { logger.info("i get some coffee"); return; } }