Library for using Crontab-like syntax in scheduling of some Kotlin Coroutines tasks to do from time to time

Overview

krontab

Maven Central Build Status KDocs

Library was created to give oppotunity to launch some things from time to time according to some schedule in runtime of applications.

How to use

There are several ways to configure and use this library:

  • From some string
  • From builder

Anyway, to start some action from time to time you will need to use one of extensions/functions:

val kronScheduler = /* creating of KronScheduler instance */;

kronScheuler.doWhile {
    // some action
    true // true - repeat on next time
}

Including in project

If you want to include krontab in your project, just add next line to your dependencies part:

implementation "dev.inmo:krontab:$krontab_version"

Next version is the latest currently for the library:

Maven Central

For old version of Gradle, instead of implementation word developers must use compile.

Config from string

Developers can use more simple way to configure repeat times is string. String configuring like a crontab, but with a little bit different meanings:

/--------------- Seconds
| /------------- Minutes
| | /----------- Hours
| | | /--------- Days of months
| | | | /------- Months
| | | | | /----- (optional) Year
| | | | | | /--- (optional) Timezone offset
| | | | | | |  / (optional) Week days
* * * * * * 0o *w

It is different with original crontab syntax for the reason, that expected that in practice developers will use seconds and minutes with more probability than months (for example) or even years. In fact, developers will use something like:

doWhile("/5 * * * *") {
    println("Called")
    true // true - repeat on next time
}

An other version:

doInfinity("/5 * * * *") {
    println("Called")
}

Both of examples will print Called message every five seconds.

Config via builder

Also, this library currently supports DSL for creating the same goals:

val kronScheduler = buildSchedule {
    seconds {
        from (0) every 5
    }
}
kronScheduler.doWhile {
    println("Called")
    true // true - repeat on next time
}

Or

val kronScheduler = buildSchedule {
    seconds {
        0 every 5
    }
}
kronScheduler.doWhile {
    println("Called")
    true // true - repeat on next time
}

Or

val kronScheduler = buildSchedule {
    seconds {
        0 every 5
    }
}
kronScheduler.doInfinity {
    println("Called")
}

All of these examples will do the same things: print Called message every five seconds.

do* functions

With regular doOnce/doWhile/doInfinity there are two types of their variations: local and timezoned. Local variations (doOnceLocal/doWhileLocal/doInfinityLocal) will pass DateTime as an argument into the block:

doInfinityLocal("/5 * * * *") {
    println(it) // will print current date time
}

Timezoned variations (doOnceTz/doWhileTz/doInfinityTz) will do the same thing but pass as an argument DateTimeTz:

doInfinityTz("/5 * * * * 0o") {
    println(it) // will print current date time in UTC
}

It is useful in cases when you need to get the time of calling and avoid extra calls to system time.

Helpful table for

No args Local DateTime Local DateTimeTz with offset of KronScheduler
Call only near time doOnce doOnceLocal doOnceTz
Call while condition is true doWhile doWhileLocal doWhileTz
Work infinity* doInfinity doInfinityLocal doInfinityTz

*Here there is an important notice, that Work infinity is not exactly infinity. Actually, that means that do while coroutine is alive and in fact executing will be stopped when coroutine became cancelled.

KronScheduler as a Flow

Any KronSchedulercan e converted to a Flow<DateTime using extension asFlow:

val kronScheduler = buildSchedule {
    seconds {
        0 every 1
    }
}

val flow = kronScheduler.asFlow()

So, in this case any operations related to flow are available and it is expected that they will work correctly. For example, it is possible to use this flow with takeWhile:

flow.takeWhile {
    condition()
}.collect {
    action()
}

Offsets

Offsets in this library works via passing parameter ending with o in any place after month config. Currently there is only one format supported for offsets: minutes of offsets. To use time zones you will need to call next method with DateTimeTz argument or nextTimeZoned method with any KronScheduler instance, but in case if this scheduler is not instance of KronSchedulerTz it will work like you passed just DateTime.

Besides, in case you wish to use time zones explicitly, you will need to get KronSchedulerTz. It is possible by:

  • Using createSimpleScheduler/buildSchedule/KrontabTemplate#toSchedule/KrontabTemplate#toKronScheduler methods with passing defaultOffset parameter
  • Using SchedulerBuilder#build/createSimpleScheduler/buildSchedule/KrontabTemplate#toSchedule/KrontabTemplate#toKronScheduler methods with casting to KronSchedulerTz in case you are pretty sure that it is timezoned KronScheduler
  • Creating your own implementation of KronSchedulerTz

Note about week days

Unlike original CRON, here week days:

  • Works as AND: cron date time will search first day which will pass requirement according all parameters including week days
  • You may use any related to numbers syntax with week days: 0-3w, 0,1,2,3w, etc.
  • Week days (like years and offsets) are optional and can be placed anywhere after month
Comments
  • Time zone aware schedules

    Time zone aware schedules

    First of all, this looks like a really useful library that fits nicely into the current project i'm working on.

    One of my needs is to have schedules on specific days in different time zones. I can't see anywhere to configure the time zone for the current schedule, isn't this supported as of now? If not, i see you are using the Klock library after a quick poke into the codebase. Klock supports time zone offsets, isn't it possible to use this feature?

    opened by kfh 13
  • `next()` returns `null` on fixed date

    `next()` returns `null` on fixed date

    I'm using this library with kotlinx-datetime. I would like to schedule a task once at a specified time, but when I execute the code that task runs immediately

    import dev.inmo.krontab.KronScheduler
    import dev.inmo.krontab.builder.buildSchedule
    import dev.inmo.krontab.doOnce
    import dev.inmo.krontab.nextOrNow
    import kotlinx.datetime.Clock
    import kotlinx.datetime.LocalDateTime
    import kotlinx.datetime.TimeZone
    import kotlinx.datetime.toLocalDateTime
    import kotlin.time.Duration.Companion.seconds
    
    suspend fun main() {
      ((Clock.System.now().also {
        println("now:\t\t\t${it.toString().replace("T", "\t\t ")}")
      }) + 6.seconds).toLocalDateTime(TimeZone.UTC)
        .also { println("should run at:\t${it.toString().replace("T", "\t\t ")}") }
        .toCron()
        .also {
          println("next:\t\t\t${it.next()?.toStringDefault()}")
          println("nextOrNow:\t\t${it.nextOrNow().toStringDefault()}")
        }
        .doOnce {
          println("Hello at\t\t${it.toStringDefault()}")
        }
    }
    
    
    fun LocalDateTime.toCron(): KronScheduler = buildSchedule {
      seconds { at(second) }
      minutes { at(minute) }
      hours { at(hour) }
      dayOfMonth { at(dayOfMonth) }
      months { at(monthNumber) }
      years { at(year) }
    }
    

    output:

    now:			2022-05-29	 10:33:18.742564200Z
    should run at:		2022-05-29	 10:33:24.742564200
    next:			null
    nextOrNow:		Sun, 29 May 2022 10:33:19 UTC
    Hello at		Sun, 29 May 2022 10:33:19 UTC
    

    If I comment out years { at(year) } or dayOfMonth { at(dayOfMonth) } I think there's a infinite loop If I comment out months { at(monthNumber) } code works fine at scheduled time

    Where is the problem?

    opened by DVDAndroid 7
  • `java.time.Duration` as a time period?

    `java.time.Duration` as a time period?

    Thanks for the amazing library. Do you see value in providing an API to schedule the task with a java.time.Duration time period? I understand that it is not exactly a crontab format.

    I could contribute if you agree to the proposal.

    opened by mangatmodi 4
  • Make Kron Scheduler DSL more flexible

    Make Kron Scheduler DSL more flexible

    First of all, still enjoying this little library :)

    So, i prefer using the builder DSL for creating schedules due to type safety and verboseness. Ie when building a time zone aware scheduler that should run a job every 5 minutes i would use something like this:

    
    val scheduler = buildSchedule(0) {
                minutes {
                    0 every 5
                }
            }
    
    

    And if i run this like the following:

    scheduler.asFlow().collect { ... }

    That gives me a timeline of all the seconds on the 5th minute since this is a minute scheduler and makes my job run every second on the 5th minute. Not exactly what i want. And yes, i know i can use the schedule which takes a string cron expression as argument instead to control the data and give me exactly one DateTimeZone back. But as stated, i want to use the DSL builder.

    So, i think in most cases you want to trigger your job only once with most schedulers so we need to control seconds, minutes and so on when we use schedulers other than the seconds scheduler. What i've ended up doing is writing a little extension functions like the following:

    
      @FlowPreview
      private fun KronScheduler.asSingleTzFlow(seconds: Int = 0): Flow<DateTimeTz> = channelFlow {
          doInfinityTz {
              send(it)
          }
      }
          .filter { it.seconds == seconds }
    
    

    Which solves this problem without a lot of fuzz :) But i was thinking that maybe this is a function that should be included in your library. I think it would be great if we had api functions for all the other schedulers than seconds like this so we can override the seconds, minutes and so forth properties in an easy and concise way.

    Thoughts ?

    opened by kfh 2
  • Add template typealias

    Add template typealias

    It is required to add some typealias like typealias KrontabTemplate = String for the krontab templates. It will give opportunity for more strict explanation of expected and incoming things for the extension functions and other places

    enhancement code 
    opened by InsanusMokrassar 2
  • Day of week schedules

    Day of week schedules

    The cron pattern supported is close to standard cron as mentioned in the docs but i can't see that day of week schedules are possible to configure, or maybe there are other ways / workarounds to support for instance monday - friday at 09:00 ?

    opened by kfh 1
Releases(v0.8.5)
  • v0.8.5(Dec 15, 2022)

    • Project is now available in owner Gitea: https://git.inmo.dev/InsanusMokrassar/-/packages/maven/dev.inmo-krontab
    • KronSchedulerTz#next with incoming DateTime now will use adjusted local time instead of unadjusted one
    • CronDateTimeSchedulerTz#next with incoming DateTime will convert that parameter to internal offset directly
    Source code(tar.gz)
    Source code(zip)
  • v0.8.4(Dec 8, 2022)

  • v0.8.3(Nov 15, 2022)

  • v0.8.2(Oct 2, 2022)

  • v0.8.1(Sep 12, 2022)

  • v0.8.0(Aug 6, 2022)

  • v0.7.5(Jul 22, 2022)

  • v0.7.4(Jul 2, 2022)

  • 0.7.3(Jun 15, 2022)

  • 0.7.2(Apr 29, 2022)

    • Versions
      • Coroutines: 1.6.1
      • Klock: 2.7.0
    • Deprecate do*Local due to their redundancy (use do* instead)
    • Add support of milliseconds as optional parameter after month (fix of #31)
    • Add support of filters for Flows with DateTime (fix of #30)
    Source code(tar.gz)
    Source code(zip)
  • 0.7.1(Feb 27, 2022)

  • 0.7.0(Dec 24, 2021)

  • 0.6.6(Nov 12, 2021)

  • 0.6.5(Sep 26, 2021)

    • Flows now use doWhile functions
    • doWhile now use additional delay (for 1 ms) for cases when block executing too fast
    • New extensions for KronScheduler: do(Once/While/Infinity)Local/do(Once/While/Infinity)Tz
    Source code(tar.gz)
    Source code(zip)
  • 0.6.4(Sep 22, 2021)

  • 0.6.3(Aug 30, 2021)

  • 0.6.2(Jul 30, 2021)

  • 0.6.1(Jun 3, 2021)

  • 0.6.0(May 25, 2021)

  • 0.5.2(Apr 24, 2021)

    • Versions
      • Kotlin: 1.4.31 -> 1.4.32
    • Supporting of weekdays
    • Supporting of timezones
      • Any KronScheduler now can be used for calling next with DateTimeTz
      • New type KronSchedulerTz
    • SchedulerFlow has been deprecated
    • New extension asTzFlow and small changes in asFlow logic
    • merge extensions now return CollectionKronScheduler instead of just KronScheduler
    Source code(tar.gz)
    Source code(zip)
  • 0.5.1(Mar 16, 2021)

  • 0.5.0(Jan 3, 2021)

    BREAKING CHANGES

    • CronDateTimeScheduler has been marked as internal and no longer accessible outside of internal functions
      • Old methods merge and plus related to CronDateTimeScheduler has been marked as deprecated and changed their parameters types - it is KronScheduler now
    • New methods merge has been added
    • KronScheduler#next method now is nullable. Use nextOrRelative/nextOrNow to get next time certainly
    • Years was added as optional part of krontab template and opportunity in SchedulerBuilder
      • New builder YearsBuilder
      • SchedulerFlow#collectSafely will be normally (without exceptions) finish when next of scheduler will return null
    • KronScheduler#doOnce will run code immediately in case when next is returning null value
    • KrontabTemplateWrapper has been added
    • New extension KrontabTemplate#toKronScheduler (works as toSchedule)
    • Fixed issue related to the fact that toNearDateTime of CronDateTime incorrectly handled months
    • Android target has been added
    Source code(tar.gz)
    Source code(zip)
  • 0.4.2(Jan 1, 2021)

  • 0.4.1(Dec 5, 2020)

    • Versions:
      • Coroutines: 1.4.1 -> 1.4.2
      • Klock: 2.0.0 -> 2.0.1
    • CronDateTimeScheduler now is public
    • New functions for CronDateTimeScheduler
    • Add CollectionKronScheduler. It will give opportunity to unite several schedulers in one
    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Nov 21, 2020)

    BREAKING CHANGES Package of project has been changed. Migration:

    • Replace in your dependencies com.insanusmokrassar:krontab by dev.inmo:krontab

    • Replace in your project all imports com.insanusmokrassar.krontab by dev.inmo.krontab

    • Versions:

      • Kotlin: 1.4.10 -> 1.4.20
      • Klock: 1.12.1 -> 2.0.0
    Source code(tar.gz)
    Source code(zip)
  • 0.3.3(Nov 9, 2020)

  • 0.3.2(Oct 10, 2020)

    • Function TimeBuilder#each was added (works as at)
    • Add opportunity to use first shortcuts:
      • Value property TimeBuilder#first for including via functions like TimeBuilder#at
      • Shortcut for kron string format f or F
    • Add opportunity to use last shortcuts:
      • Value property TimeBuilder#last for including via functions like TimeBuilder#at
      • Shortcut for kron string format l or L
    Source code(tar.gz)
    Source code(zip)
  • 0.3.1(Oct 8, 2020)

Scala 3 Standard Library with bracket syntax.

Scala 3 Library with braces Scala adds a terrible new feature, optional braces, which allow use indentation instead of braces. The new syntax is widel

Glavo 10 Dec 30, 2021
A funny project to help you test your BNF syntax

Readme The idea of this project is to implement a BNF expression compiler. We could use BNF to design some syntax like Arithmetic expression. <factor>

Jack Chen 4 Dec 21, 2022
To-do-List - Creating a Reminders and Tasks app with Kotlin

To do List ?? App de Lembretes e Tarefas com Kotlin Telas do App Tecnologias Kot

Alini Rodrigues Ferreira 4 May 18, 2022
TakeNotes, taking care of your tasks and your health

Take Notes - Para tornar sua rotina mais Saudável TakeNotes, cuidando de suas tarefas e de sua saúde Sobre • Funcionalidades • Layout • Como executar

null 0 Dec 7, 2021
InterAcao: tasks shared between people in a condominium or the same community

Projeto Integrador - Generation Brasil ?? ?? Interação ?? ?? Sobre • Funcionalidades • Implementações futuras • Layout • Como executar • Tecnologias •

Ana Clara Fagundes 3 Aug 8, 2022
Taskify is a mobile application used to create and schedule tasks in your TODO list

Taskify is a mobile application used to create and schedule tasks in your TODO list. It is built upon the new Maaterial 3 UI components with the MVVM pattern and the latest Jetpack components.

Robert Muriithi 2 Jun 25, 2022
Execute asynchronous batch tasks with predefined or custom UI in Android.

AndroidBatchWorker Execute asynchronous batch tasks with predefined or custom UI in Android. Import Add JitPack repository to your project level build

Nowrose Muhammad Ragib 3 Nov 8, 2022
Kotlin Example of how to organize your code using MVC and some patterns seen in class

Kotlin Example of how to organize your code using MVC and some patterns seen in class

José Luis González Sánchez 3 Mar 23, 2022
A lightweight library for requesting and consuming Activity Results using coroutines.

SuspendActivityResult A lightweight library for requesting and consuming Activity Results using coroutines, it's usage is as simple as: val uri = Acti

Hicham Boushaba 71 Dec 23, 2022
DS-for-Kotlin - Some classic data sturctures write in kotlin for fun

DS-for-Kotlin Just write some classic data structure by kotlin during my leisure

ccyyxx 2 Jan 30, 2022
An implementation of MediatR on JVM for Spring using Kotlin coroutines

Kpring MediatR In this project, an attempt has been made to implement the mediator pattern on the JVM with simplicity using Kotlin with native corouti

Mahdi Bohloul 4 Aug 6, 2022
Simple Todo list API using Spring-Boot, Webflux, Kotlin, Coroutines, & PostgreSQL

Simple Todo list API using Spring-Boot, Webflux, Kotlin, Coroutines, & PostgreSQL

Sami Eljabali 9 Jul 26, 2022
App built using Kotlin, Dagger Hilt, Room Database, Coroutines, Flow, AndroidX Glance, WorkManager, Coil etc.

An article sharing platform where you can personalize, subscribe to your favorite topics, get daily-read reminders, etc. App built using Kotlin, Dagger Hilt, Room Database, Coroutines, Flow, AndroidX Glance, WorkManager, Coil etc.

Kasem SM 484 Jan 3, 2023
FlowExt is a Kotlin Multiplatform library, that provides many operators and extensions to Kotlin Coroutines Flow

FlowExt | Kotlinx Coroutines Flow Extensions | Kotlinx Coroutines Flow Extensions. Extensions to the Kotlin Flow library | kotlin-flow-extensions | Coroutines Flow Extensions | Kotlin Flow extensions | kotlin flow extensions | Flow extensions

Petrus Nguyễn Thái Học 151 Jan 1, 2023
Some useful Android Kotlin utilities

Android-Kotlin-utilities Some useful Android Kotlin utilities Any PR are welcomed :) Please put your code in several files like this. it helps others

Kaaveh Mohamedi 6 Oct 12, 2021
Map-vs-list-comparator - The project compares the time needed to find a given element in a map vs the time needed to find a given element in a list.

Map vs List Comparator The project compares the time needed to find a given element in a map vs the time needed to find a given element in a list. To

null 0 Jan 4, 2022
🦁 A Disney app using transformation motions based on MVVM (ViewModel, Coroutines, Flow, LiveData, Room, Repository, Koin) architecture.

DisneyMotions A demo Disney app using transformation motions based on MVVM architecture. The motion system is included in the 1.2.0-alpha05 released m

Jaewoong Eum 1.4k Jan 2, 2023
Example of using coroutines with Spring MVC

This is an example of using coroutines with Spring MVC (not webflux!) DemoController uses https://github.com/joost-de-vries/spring-coroutine, but sinc

Tiberiu Tofan 4 Dec 9, 2022
🛒 Mercado Libre App Clone using modern Android development with Hilt, Coroutines, Jetpack (Room, ViewModel), and Jetpack Compose based on MVVM architecture.

Meli Clone ?? Mercado Libre App Clone using modern Android development with Hilt, Coroutines, Jetpack (Room, ViewModel), and Jetpack Compose based on

Esteban Aragon 7 Sep 22, 2022