Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/kevincianfarini/cardiologist

Build job schedules with kotlinx-datetime and kotlinx-coroutines
https://github.com/kevincianfarini/cardiologist

cron cronjob kotlin kotlin-coroutines kotlin-datetime kotlin-multiplatform kotlin-multiplatform-library kotlinx-coroutines kotlinx-datetime

Last synced: 2 days ago
JSON representation

Build job schedules with kotlinx-datetime and kotlinx-coroutines

Awesome Lists containing this project

README

        

# Cardiologist

Build job schedules with [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) and [kotlinx-coroutines](https://github.com/Kotlin/kotlinx.coroutines).

```kt
val tz = TimeZone.of("America/New_York")
Clock.System.schedulePulse(atSecond = 0).beat { scheduled, occurred ->
println("A pulse was scheduled in $tz for ${scheduled.toLocalDateTime(tz)} and occurred at ${occurred.toLocalDateTime(tz)}.")
}
```

```
A pulse was scheduled in America/New_York for 2025-01-11T08:41 and occurred at 2025-01-11T08:41:00.005227606
A pulse was scheduled in America/New_York for 2025-01-11T08:42 and occurred at 2025-01-11T08:42:00.001463582
A pulse was scheduled in America/New_York for 2025-01-11T08:43 and occurred at 2025-01-11T08:43:00.001028731
A pulse was scheduled in America/New_York for 2025-01-11T08:44 and occurred at 2025-01-11T08:44:00.001037604
A pulse was scheduled in America/New_York for 2025-01-11T08:45 and occurred at 2025-01-11T08:45:00.001025281
A pulse was scheduled in America/New_York for 2025-01-11T08:46 and occurred at 2025-01-11T08:46:00.001062597
A pulse was scheduled in America/New_York for 2025-01-11T08:47 and occurred at 2025-01-11T08:47:00.000846953
```

## Download

```toml
[versions]
cardiologist = "0.3.1"

[libraries]
cardiologist = { module = "io.github.kevincianfarini.cardiologist:cardiologist", version.ref = "cardiologist" }

```

## Introduction

Cardiologist integrates with kotlinx-datetime to provide you scheduling based on `Instant`, `LocalDateTime`,
and `LocalTime`, and integrates with kotlinx-coroutines to provide a suspending API to trigger pending jobs.

Simple suspending functions are available to delay until a given moment in time.

```kt
Clock.System.delayUntil(instant = Instant.DISTANT_FUTURE)
Clock.System.delayUntil(dateTime = LocalDateTime.MAX, timeZone = TimeZone.UTC)
```

...or suspending for a given period of time.

```kt
Clock.System.delayFor(period = DateTimePeriod(months = 1, days = 2), timeZone = TimeZone.UTC)
```

...or suspending until the next time a `LocalTime` occurs in a certain time zone.

```kt
val midnight = LocalTime(hour = 0, minute = 0)
Clock.System.delayUntilNext(time = midnight, timeZone = TimeZone.UTC)
```

Repeating intervals are provided as a `Pulse`, a type which holds a reccurence cadence.

```kt
val hourlyPulse: Pulse = Clock.System.intervalPulse(interval = 1.hours)
val dailyPulse: Pulse = Clock.System.intervalPulse(
period = DateTimePeriod(days = 1),
timeZone = TimeZone.UTC,
)
```

Pulse schedules can be built with a cron like API.

```kt
// Schedules a pulse to occur on the 5th of every month at 12:30 in UTC.
val scheduledPulse = Clock.System.schedulePulse(
timeZone = TimeZone.UTC,
atSecond = 0,
atMinute = 30,
atHour = 12,
onDayOfMonth = 5,
)
```

...and can be invoked by calling `Pulse.beat`.

```kt
scheduledPulse.beat { instant -> println("$instant") }
```

Beating a pulse is a backpressure sensitive operation. If your job has not completed when the next
pulse is scheduled to occur, it will by default be cancelled. Cardiologist provides another mode
to beat a pulse which allow jobs to run concurrently.

```kt
import io.github.kevincianfarini.cardiologist.RecurringJobMode.*

// Cancels previous job when next job is scheduled to occur.
hourlyPulse.beat(mode = CancellingSequential) { instant -> longRunningOperation(instant) }

// Allows jobs to run concurrently if previous job is still active.
hourlyPulse.beat(mode = Concurrent) { instant -> longRunningOperation(instant) }
```

## Cardiologist is not a replacement for crontab(5) or Android WorkManager.

Cardiologist is an _in process_ job scheduling library. It is meant to run concurrently to the rest of
your process, not as a separate process. Use cases include job scheduling within a long-lived process like
a server or a daemon.

```kt
// With ktor, for example.
fun main() = runBlocking { // this: CoroutineScope
this.embeddedServer(Netty, port = 8080) { /* omitted */ }.start(wait = false)
launch { recurringJob() }
}

private suspend fun recurringJob() {
Clock.System.schedulePulse(
onDayOfMonth = 1,
atHour = 0,
atMinute = 0,
atSecond = 0
).beat { instant -> someWork(instant) }
}
```

Cron jobs and Android's WorkManager leverage standalone processes and will launch your program as a separate processes.
This is outside the scope of Cadiologist's goals.