Search code examples
kotlintimerkotlin-coroutinesdelaycoroutine

Run action every minute sharp using kotlin coroutines


I believe this can be done, just don't know that is the best API to easily achieve this...

Basically, I have the following method:

private val tickerPeriod = 1.minutes

private suspend fun saveCachedValuesPeriodically() {
        delay(getInitialDelay())
        while (currentCoroutineContext().isActive) {
            saveCachedValues()
            delay(tickerPeriod)
        }
}

I want to run the method saveCachedValues() every minute with precision to the second, using kotlin coroutines. So, if the first timestamp happens with 0 seconds all the following should also be like that.

But what is happening with the code above is that, due to the time spent on savedCachedValues(), the milliseconds will increase at every iteration, and after some iterations, the seconds part will also be different...

What would be a nice way to fix that?


Solution

  • Using the answer from @Jorn as a basis, I ended up with the following solution to address my comment in his response.

    private lateinit var nextRun: ZonedDateTime
    private suspend fun saveCachedValuesPeriodically() {
        delay(getInitialDelay())
        while (currentCoroutineContext().isActive) {
            val now = dateTimeProvider.getCurrentZonedDateTimeUTC()
            nextRun= now.truncatedTo(ChronoUnit.MINUTES)
                .plus(tickerPeriod.toJavaDuration())
            saveCachedValues()
            delay(java.time.Duration.between(now, nextRun).toKotlinDuration())
        }
    }