I want to understand difference between hazelcast methods for IScheduledExecutorService for prevent duplicate tasks. I have two java app with HazelcastInstance. Respectively I have hazelcast cluster with two HazelcastInstances (servers). I use IMap and want to reset AtomicLong every midnight.
config.getScheduledExecutorConfig("my scheduler")
.setPoolSize(16)
.setCapacity(100)
.setDurability(1);
class DelayedResetTask implements Runnable, HazelcastInstanceAware, Serializable {
static final long serialVersionUID = -7588380448693010399L;
private transient HazelcastInstance client;
@Override
public void run() {
final IMap<Long, AtomicLong> map = client.getMap(HazelcastConfiguration.mapName);
final ILogger logger = client.getLoggingService().getLogger(HazelcastInstance.class);
logger.info("Show data in cache before reset: " + map.entrySet());
map.keySet().forEach(key -> map.put(key, new AtomicLong(0)));
logger.info("Data was reseted: " + map.entrySet());
}
@Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) { this.client = hazelcastInstance; }
}
private void resetAtMidnight() {
final Long midnight = LocalDateTime.now().until(LocalDate.now().plusDays(1).atStartOfDay(), ChronoUnit.MINUTES);
executor.scheduleAtFixedRate(new DelayedResetTask(), midnight, TimeUnit.DAYS.toMinutes(1), TimeUnit.MINUTES);
}
I don't want to execute this task on each instance in parallel. After reading documentation documentation I don't understand how I can execute reset in both servers for one step (without duplicate tasks, without execution on both servers at one time).
What method I can use for my task scheduleOnAllMembersAtFixedRate
or scheduleAtFixedRate
or scheduleOnMembersAtFixedRate
.
How to prevent duplicate tasks when run same IScheduledExecutorService on apps in cluster?
You need to run your code only once in the cluster, since the map you are resetting can be accessed from any member. Both members access to the same map instance, only the entries are kept in different members. You can use scheduleAtFixedRate
to run it once.
Additionally, you do not need to call IMap#keySet().forEach()
to traverse over all entries in the map. Instead, you can use EntryProcessor
as below:
public static class DelayedResetTask implements Runnable, HazelcastInstanceAware, Serializable {
static final long serialVersionUID = -7588380448693010399L;
private transient HazelcastInstance client;
@Override
public void run() {
final IMap<Long, AtomicLong> map = client.getMap(HazelcastConfiguration.mapName);
final ILogger logger = client.getLoggingService().getLogger(HazelcastInstance.class);
logger.info("Show data in cache before reset: " + map.entrySet());
map.executeOnEntries(new AbstractEntryProcessor() {
@Override
public Object process(Map.Entry entry) {
entry.setValue(new AtomicLong(0));
return null;
}
});
logger.info("Data was reseted: " + map.entrySet());
}
@Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) { this.client = hazelcastInstance; }