All Downloads are FREE. Search and download functionalities are using the official Maven repository.

.hexagon_scheduler.1.4.4.source-code.CronScheduler.kt Maven / Gradle / Ivy

package com.hexagonkt.scheduler

import com.hexagonkt.helpers.fail
import com.cronutils.model.CronType.QUARTZ
import com.cronutils.model.definition.CronDefinitionBuilder.instanceDefinitionFor as cronDefinition
import com.cronutils.model.time.ExecutionTime
import com.cronutils.parser.CronParser
import com.hexagonkt.logging.Logger

import java.lang.Runtime.getRuntime
import java.time.ZonedDateTime
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.TimeUnit.SECONDS

/**
 * Scheduler to execute tasks repeatedly. After using it, you should call the [shutdown] method. If
 * the JVM finishes without calling [shutdown], it will be called upon JVM termination.
 *
 * @param threads Number of threads used by the thread pool. By default it is equals to the number
 *  of processors.
 *
 * @sample com.hexagonkt.scheduler.CronSchedulerSamplesTest.callbackExecutedProperly
 */
class CronScheduler(threads: Int = getRuntime().availableProcessors()) {
    private val log: Logger = Logger(this::class)

    private val scheduler = ScheduledThreadPoolExecutor(threads)
    private val cronParser = CronParser(cronDefinition(QUARTZ))

    init {
        getRuntime().addShutdownHook(Thread { shutdown() })
    }

    /**
     * Schedules a block of code to be executed repeatedly by a
     * [Cron](https://en.wikipedia.org/wiki/Cron) expresion.
     *
     * @param cronExpression Periodicity of the task in Cron format.
     * @param callback Task code to be executed periodically.
     */
    fun schedule(cronExpression: String, callback: () -> Unit) {
        val cron = cronParser.parse(cronExpression)
        val cronExecution = ExecutionTime.forCron(cron)

        scheduler.schedule({ function(callback, cronExecution) }, delay(cronExecution), SECONDS)
    }

    /**
     * Shuts down this scheduler's thread pool. Calling over an already closed scheduler does not
     * have any effect. It is called by the JVM when it is shut down.
     */
    fun shutdown() {
        scheduler.shutdown()
    }

    private fun delay(cronExecution: ExecutionTime): Long =
        cronExecution.timeToNextExecution(ZonedDateTime.now()).orElseThrow { fail }.seconds

    private fun function(callback: () -> Unit, cronExecution: ExecutionTime) {
        try {
            callback()
        }
        catch (e: Exception) {
            log.error(e) { "Error executing cron job" }
        }

        scheduler.schedule({ function(callback, cronExecution) }, delay(cronExecution), SECONDS)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy