Spring @Случайная задержка по фиксированной аннотации

Я использую аннотацию @Scheduled из фрейма Spring для вызова метода. Но у меня есть несколько узлов в моей настройке, и я не хочу, чтобы все они запускались точно в одно и то же время. Поэтому я хотел бы установить случайное значение для начальной задержки, чтобы компенсировать их друг от друга.

import org.springframework.scheduling.annotation.Scheduled;

@Scheduled(fixedRate = 600000, initialDelay = <random number between 0 and 10 minutes> )

К сожалению, мне разрешено использовать здесь постоянное выражение. Есть ли другой способ обойти это? Я думал об использовании языка выражения Spring.

Ответ 1

Вы можете настроить initialDelay с помощью Spring Expression Language:

@Scheduled(fixedRate = 600000, initialDelayString = "#{ T(java.util.concurrent.ThreadLocalRandom).current().nextInt(10*60*1000) }" )

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

Ответ 2

Чтобы сделать начальную задержку случайным образом где-то между 0 и fixedRate, попробуйте это:

@Scheduled(fixedDelayString = "${some.delay}", initialDelayString = "${random.int(${some.delay})}")

Где вы определяете some.delay (но выбираете более подходящее имя) как 10 минут как свойство, подобное вашему приложению .properties или эквивалент.

some.delay = 600000

Конечно, если вы хотите быть ленивым и жестким кодом, вы всегда можете просто использовать ${random.int(600000)}

Ответ 3

Имейте в виду, что initialDelayString оценивается только один раз при запуске, и эти значения используются всегда, когда задание запланировано.

См. org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor # processScheduled

Ответ 4

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

@Scheduled(fixedDelayString = "#{new Double((T(java.lang.Math).random() + 1) * 5000).intValue()}")

Ответ 5

В котлине это работает:

@Component
class MyJob {
   companion object {
      const val INTERVAL = 24*3600*1000L // once a day
   }

   @Scheduled(fixedRate = INTERVAL, initialDelayString = "\${random.long($INTERVAL)}")
   fun doDaily() {
      ...
   }
}

Ответ 6

Или вы можете просто добавить Thread.sleep(...) в конце вашей функции.

@Scheduled(fixedDelay = 10000)
public void replicateData() {

    ... do stuff ...

    try {
        Thread.sleep(RandomUtils.nextLong(1000, 10000));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}