nim-schedules
A Nim scheduler library that lets you kick off jobs at regular intervals.
Example usage:
schedules: every(seconds=1, id="tick", throttle=1, async=true): echo("async tick ", now()) await sleepAsync(2000) every(seconds=1, id="tick", throttle=1): echo("sync tick ", now())
Types
BeaterAsyncProc = proc (): Future[void] {...}{.gcsafe, closure.}
BeaterThreadProc = proc (): void {...}{.gcsafe, thread.}
Throttler = ref object num: int beats: seq[Future[void]]
- Throttle the total number of beats.
BeaterKind {...}{.pure.} = enum bkInterval, bkCron
Beater = ref object of RootObj id: string startTime: DateTime endTime: Option[DateTime] beaterProc: BeaterAsyncProc throttler: Throttler case kind*: BeaterKind of bkInterval: interval*: TimeInterval of bkCron: cron*: Cron
- Beater generates beats for the next runs.
Settings = ref object appName*: string errorHandler*: proc (fut: Future[void]) {...}{.closure, gcsafe.}
Scheduler = ref object settings: Settings beaters: seq[Beater] futures: seq[Future[void]]
Vars
logger = newConsoleLogger(lvlAll, defaultFmtStr, false)
- By default, the logger is attached to no handlers. If you want to show logs, please call addHandler(logger).
Procs
proc initThrottler(num: int = 1): Throttler {...}{.raises: [], tags: [].}
- Initialize the total number of beats allowed to be scheduled. By default, it's 1. If it's greater than 1, then more than one beats can be scheduled simultaneously.
proc throttled(self: Throttler): bool {...}{.raises: [], tags: [].}
- Whether the throttler is allowed to schedule more beats.
proc submit(self: Throttler; fut: Future[void]) {...}{.raises: [], tags: [].}
- Submit a new future to the throttler. WARNING: this function does not perform throttling check.
proc `$`(beater: Beater): string {...}{.raises: [], tags: [].}
proc initBeater(interval: TimeInterval; asyncProc: BeaterAsyncProc; startTime: Option[DateTime] = none(DateTime); endTime: Option[DateTime] = none(DateTime); id: string = ""; throttleNum: int = 1): Beater {...}{.raises: [UnpackError], tags: [TimeEffect].}
-
Initialize a Beater, which kind is bkInterval.
startTime and endTime are optional.
proc initBeater(interval: TimeInterval; threadProc: BeaterThreadProc; startTime: Option[DateTime] = none(DateTime); endTime: Option[DateTime] = none(DateTime); id: string = ""; throttleNum: int = 1): Beater {...}{.raises: [UnpackError], tags: [TimeEffect].}
-
Initialize a Beater, which kind is bkInterval.
startTime and endTime are optional.
proc initBeater(cron: Cron; threadProc: BeaterThreadProc; startTime: Option[DateTime] = none(DateTime); endTime: Option[DateTime] = none(DateTime); id: string = ""; throttleNum: int = 1): Beater {...}{.raises: [UnpackError], tags: [TimeEffect].}
-
Initialize a Beater, which kind is bkInterval.
startTime and endTime are optional.
proc initBeater(cron: Cron; asyncProc: BeaterAsyncProc; startTime: Option[DateTime] = none(DateTime); endTime: Option[DateTime] = none(DateTime); id: string = ""; throttleNum: int = 1): Beater {...}{.raises: [UnpackError], tags: [TimeEffect].}
-
Initialize a Beater, which kind is bkInterval.
startTime and endTime are optional.
proc fireTime(self: Beater; prev: Option[DateTime]; now: DateTime): Option[DateTime] {...}{. raises: [UnpackError, Exception, KeyError], tags: [RootEffect].}
-
Returns the next fire time of a task execution.
For bkInterval, it has below rules:
- For the 1st run,
- Choose startTime if it hasn't come.
- Choose the next startTime + N * interval that hasn't come.
- For the rest of runs,
- Choose prev + interval.
If self.endTime is set and greater than the fire time, a none(DateTime) is returned.
- For the 1st run,
proc fire(self: Beater): owned(Future[void]) {...}{.raises: [Exception, FutureError], tags: [RootEffect, TimeEffect].}
- Fire beats as async loop until no beats can be scheduled.
proc newSettings(appName = ""; errorHandler: proc (fut: Future[void]) {...}{.closure, gcsafe.} = nil): Settings {...}{. raises: [], tags: [].}
proc initScheduler(settings: Settings): Scheduler {...}{.raises: [], tags: [].}
- Initialize a scheduler.
proc register(self: Scheduler; beater: Beater) {...}{.raises: [], tags: [].}
- Register a beater.
proc idle(self: Scheduler): owned(Future[void]) {...}{.raises: [Exception, FutureError], tags: [RootEffect, TimeEffect].}
- Idle the scheduler. It prevents the scheduler from shutdown when no beats is running.
proc start(self: Scheduler): owned(Future[void]) {...}{.raises: [Exception, FutureError], tags: [RootEffect, TimeEffect].}
- Start the scheduler.
proc serve(self: Scheduler) {...}{.raises: [Exception, ValueError, FutureError, UnpackError, OSError, IndexError], tags: [RootEffect, TimeEffect].}
- Serve the scheduler. It's a blocking function.
proc waitFor(self: Scheduler) {...}{.raises: [Exception, ValueError, FutureError, UnpackError, OSError, IndexError], tags: [RootEffect, TimeEffect].}
- Run all beats til they're completed.
Macros
macro scheduler(sched: untyped; body: untyped): typed
-
Initialize a scheduler and register code blocks as beats.
You'll use it when you want to mix using nim-schedules with some other libraries, such as jester, etc.
macro schedules(body: untyped): untyped
-
Initialize a scheduler, register code blocks as beats, and run it as a blocking application.
You'll use it when the scheduled jobs are the only thing your programm will need to handle.