HazelCast FencedLock не всегда успешно блокирует метод для других нод

Решил синхронизировать метод между 2 нодами приложения. Для этого взял FencedLock решение из библиотеки HazelCast. Все сделал по документации, ноды друг-друга увидели и объединились в кластер. Метод тоже синхронизировался, начал отрабатывать по 1 разу, но время от времени происходит дубляж работы метода(не часто).

Не могу понять с чем это связано! Проблему я решил тем, что создал распределенный объект IMap, который поместил внутрь метода и исходя из него стал либо отрабатывать метод, либо игнорировать. Мне кажется, это больше похоже на костыль.

Нет ли пути решения данной проблемы через fencedLock-и и его конфиги?

P.S. Просьба не ссылаться на какие-то ключевые слова и отправлять меня в google, так как документации крайне мало и нет примеров работающего кода. Буду благодарен развернутому ответу.

hazelCast.yaml файл:

hazelcast:
  network:
    join:
      multicast:
        enabled: true

HazelCastConfiguration класс:

@Configuration
public class HazelCastConfiguration {

    @Bean
    public com.hazelcast.config.Config hazelCastConfig() {
        return new Config();
    }

    @Bean
    public HazelcastInstance hazelcastInstance(Config hazelCastConfig) {
        return Hazelcast.newHazelcastInstance(hazelCastConfig);
    }

    @Bean
    public IMap<String, LocalDateTime> timeMap(@Qualifier("hazelcastInstance") HazelcastInstance hazelcastInstance) {
        return hazelcastInstance.getMap("hazelcastTimeMap");
    }

Над методом я повесил Spring Scheduler и настроил его cron на работу каждые 5 секунд.

Метод до того как я добавил IMap:

@Scheduled(cron = "0/5 * * * * *")
    public void sentMessage() {
        FencedLock lock = hazelcastInstance.getCPSubsystem().getLock("myLock");
        if (lock.tryLock()) {
            try {
                System.out.println("test message!" + LocalDateTime.now());
            } finally {
                lock.unlock();
            }
        }
    }

Результат его работы между 2 нодами:

Нода 1:

введите сюда описание изображения

Нода 2:

введите сюда описание изображения

После добавление IMap и ориентирования по нему, проблему ушла.

Метод после добавления IMap:

@Scheduled(cron = "0/5 * * * * *")
    public void sentMessage() {
        FencedLock lock = hazelcastInstance.getCPSubsystem().getLock("myLock");
        if (lock.tryLock()) {
            try {
                LocalDateTime date = timeMap.get("message");
                if (date == null || LocalDateTime.now().isAfter(date)) {
                    System.out.println("test message!" + LocalDateTime.now());
                    timeMap.put("message", LocalDateTime.now().plusSeconds(4));
                }
            } finally {
                lock.unlock();
            }
        }
    }

Ответы (1 шт):

Автор решения: Alexander Pavlov

Спринг, да и ОС, не гарантируют тебе одновременное исполнение @Scheduled(cron = "0/5 * * * * *") + тело метода маленькое и отрабатывает быстро.

В итоге, иногда получается, что на одном узле вызов по расписанию успевает взять лок, напечатать и отпустить лок. В этот момент до лока добирается второй, но лок никто не держит, поэтому второй тоже отрабатывает.

IMap как раз эту проблему решает. Решение не костыльное, а вполне нормальное.

По другому можно было бы сделать за счёт удержания лока подольше, чтобы второй узел успел проснуться, попытаться взять лок и обломиться. Например, Thread.sleep(100) - но это тоже не будет 100% гарантией, потому что второй может опоздать и на больше, чем 100мс - например, у него случился GC. Это даже по твоим логами видно - один раз исполнение в X.008ms, другой раз в X.171ms.

→ Ссылка