9

as stated in the title of a question, I need to set Spring Scheduler that will run method to load something from database into memory, every day around 4AM

The thing is that I have multiple instances of this server and I don't want all to start executing at the same time cause it will slow down the DB. So I want the time to be at a random minute somewhere between 4:00AM and 4:30AM

So lets say one instance will start everyday at 4:03AM, the other at 4:09AM, third at 4:21AM etc. The execution of query lasts for 1 minute.

Is this possible to do with cron expression, but without using $RANDOM bash (cause I think I dont have it) , or maybe I need to inject this random value some other way into

@Scheduled(cron="* randomMinuteValue 4 * * *")
tibortru
  • 692
  • 5
  • 26
  • I would not do it like this. Why don't you start them all at the same time and throttle them based on how many connections are being used in the database connection pool. – Essex Boy Dec 07 '16 at 11:43
  • My mistake I wrote I have multiple service instances but I wanted to say server instances, therefore each server will try to connect to DB at the same time. And I dont have control of one server instance from the other, to throttle them. Sry for the mistake I wrote :( @EssexBoy – tibortru Dec 07 '16 at 11:50
  • What database are you using? – Essex Boy Dec 07 '16 at 12:40
  • @EssexBoy mysql – tibortru Dec 07 '16 at 13:16
  • 1
    I think I found a way by using RandomValuePropertySource with that I can inject any random int for given range like so @Scheduled(cron='0 ${random.int[0,30]} 4 * * ?') – tibortru Dec 07 '16 at 13:19
  • @tibortru Did it work for You? In my case the only first call is done with random value... then the same value is used each time. – kingkong Apr 15 '19 at 20:47
  • @kingkong yes that is how I wanted it to work, because the value that I assigned randomly is only assigned once at the start of the application, but it was good enough for me. If you want random value to be refreshed with new value each time cron is scheduled to run, then I think you will have to override bean definition and not use annotation. – tibortru Apr 16 '19 at 13:37

2 Answers2

19

If you use Spring Boot, you can use RandomValuePropertySource:

@Scheduled(cron="0 ${random.int[0,30]} 4 * * ?")

Note that the random value is calculated at Spring context initialization time (i.e. usually at app startup), afterwards the same time will be used every day until restart.

It is not completely random but suits the OP's problem of avoiding an activity peak.

sleske
  • 81,358
  • 34
  • 189
  • 227
tibortru
  • 692
  • 5
  • 26
  • Note that the random value is calculated at initialization time, the same time will be used every day. It is not completely random but suits the OP's problem of avoiding an activity peak. – Florian F Mar 10 '21 at 07:28
  • @FlorianF: Good point, took the liberty of adding it to the answer. – sleske Jun 07 '23 at 08:49
5

In case you have java 8 but not spring boot, you can try the following:

@Scheduled(cron = "0 #{new java.util.Random().nextInt(30)} 4 * * ?")
dvtoever
  • 3,896
  • 1
  • 28
  • 29