Schedule Queues

Clock with several indicators lighting up in green every N minutes (multiple triggers within an hour).

Table of contents


Problem

When using Vapor Queues to schedule jobs, the typical API is:

app.queues
    .schedule(MyJob()).hourly().at(0)

This schedules once per hour. If we want to run it every N minutes (e.g., every 5, 10, or 15), we have to manually register multiple .at(…) calls, which results in repetitive code, prone to errors (duplicated/forgotten minutes), and difficult to read.


Solution

We extract a helper over Application.Queues that registers the same ScheduledJob multiple times within the hour using a stride with step minutes. This way, with a single call we express: “run it every N minutes”.

extension Application.Queues {
    func scheduleEvery(
        _ job: ScheduledJob,
        minutes: Int
    ) {
        for minuteOffset in stride(
            from: 0,
            to: 60,
            by: minutes
        ) {
            schedule(job).hourly()
                .at(.init(integerLiteral: minuteOffset))
        }
    }
}

Key points:

  • Uses stride(from: 0, to: 60, by: minutes) to generate minute offsets within the hour.
  • For each offset it registers hourly().at(…), avoiding logic duplication.
  • If minutes doesn’t divide 60, the last execution will be the largest multiple < 60 (e.g., minutes = 7 ⇒ 0, 7, 14, …, 56).

Result

Usage example:

func configure(_ app: Application) throws {
    app.queues.scheduleEvery(MyJob(), minutes: 5)
}

A concise and self-expressive API for short periodic tasks:

  • Less boilerplate: a single call registers all triggers.
  • Fewer errors: no manual lists of .at(…) or duplicated minutes.
  • Readable and testable: the pattern is evident and easy to verify.

Keep coding, keep running 🏃‍♂️