Open-source project
sidekiq-scheduler/sidekiq-scheduler avatar
sidekiq-scheduler/sidekiq-scheduler

sidekiq-scheduler: Cron Scheduling for Sidekiq

Lightweight job scheduler extension for Sidekiq

1,754 stars241 forksRubyMIT

At a glance

What is it?
sidekiq-scheduler adds recurring and one-time schedules to Ruby jobs processed by Sidekiq. It is a focused extension for applications that need cron-style enqueueing without designing a separate scheduling service.
Who is it for?
sidekiq-scheduler is appropriate for Ruby applications that already use Sidekiq and need schedules expressed in YAML, including recurring jobs, delayed one-time jobs, alternate queues, and runtime schedule reloads. It is a poor fit for deployments that do not run Sidekiq, require independently operated scheduling infrastructure, or need guarantees beyond those documented here.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why sidekiq-scheduler Fits a Sidekiq Application

sidekiq-scheduler addresses a specific gap in ordinary Sidekiq job definitions: when a known Ruby worker class should be enqueued. It extends Sidekiq with scheduling that resembles a cron utility, so recurring and one-time job definitions can remain beside the application configuration. The intended users are Ruby teams that already use Sidekiq for background processing and want schedules loaded from `sidekiq.yml`.

The extension does not replace Sidekiq's execution model. A schedule causes a job to enter Sidekiq, and Sidekiq workers still perform the actual work. That division matters for architecture: scheduling decides when work is queued, while Sidekiq handles queueing and execution. The project is therefore more suitable for a scheduled Sidekiq job than for a workflow engine that must manage dependencies, completion conditions, or human approval.

The documented Hello World example uses a class that includes `Sidekiq::Job`. The README recommends this form because `Sidekiq::Job` was introduced in Sidekiq 6.3 as an alias for `Sidekiq::Worker`, and `Sidekiq::Worker` is officially deprecated in Sidekiq 7. This compatibility detail should be checked before copying an older Sidekiq integration into a current application.

A further constraint is that sidekiq-scheduler parses schedules with Fugit. The README says Fugit supports cron strings with up to six arguments. The examples therefore include seconds as the first field: `0 * * * * *` means execution at second zero of every minute. A conventional five-field cron expression copied from another system may not match the documented syntax.

Schedule Loading, Enqueueing, and Worker Execution

The configuration path is `:scheduler:` followed by `:schedule:` in `config/sidekiq.yml`. Each schedule entry identifies a worker and includes a timing rule. The scheduler can derive the worker class from the entry name, or the entry can set `class` explicitly. It then enqueues that worker with any configured arguments and queue.

At process startup, the command loads a Ruby file containing the job definition before starting Sidekiq. The documented output shows a schedule-loading phase, a `Scheduling HelloWorld` message containing the cron and class, and then `Schedules Loaded`. The worker output appears later when Sidekiq runs the enqueued job. That sequence separates schedule registration from job execution.

Arguments are passed through `args`. With `keyword_argument: true`, sidekiq-scheduler deconstructs a hash in `args` into keyword arguments. This supports a worker such as an `ActiveJob::Base` subclass whose `perform` method declares named keyword parameters. The README does not describe automatic argument conversion for other worker styles beyond this option, so argument shape and method signature must be reviewed together.

A schedule may also select a queue with `queue: slow`. The `listened_queues_only` setting can restrict pushes to queues that the running Sidekiq process listens to, although it defaults to `false`. Queue selection and process configuration therefore need to agree. The scheduler can enqueue a job, but Sidekiq must be configured to consume the selected queue for a worker to process it.

Metadata is optional. With `include_metadata: true`, the worker receives an additional final argument containing at least `:scheduled_at`, described as the epoch when the job was scheduled to run. The `perform` method must include that final parameter when the entry enables it.

Installing and Running the Hello World Schedule

The README provides a direct RubyGems installation command. This installs the gem, but an application still needs a Sidekiq configuration and a Ruby file that defines the worker class.

Use the documented installation command:

bash
gem install sidekiq-scheduler

The command installs the Ruby gem in the local Ruby environment. The README does not add any required environment variables or companion packages for this example.

Define the worker in a file named `hello-scheduler.rb`. Including `Sidekiq::Job` connects the class to Sidekiq's worker interface:

ruby
require 'sidekiq-scheduler'

class HelloWorld
  include Sidekiq::Job

  def perform
    puts 'Hello world'
  end
end

Add the schedule to `config/sidekiq.yml`. The entry name is `hello_world`, while `class` points that schedule to `HelloWorld`:

yaml
:scheduler:
  :schedule:
    hello_world:
      cron: '0 * * * * *'
      class: HelloWorld

Start Sidekiq with the Ruby file loaded through `-r`:

bash
sidekiq -r ./hello-scheduler.rb

The documented log sequence shows `Loading Schedule`, `Scheduling HelloWorld`, and `Schedules Loaded` during startup. At the next minute boundary, the example output shows the `HelloWorld` job starting, printing `Hello world`, and completing. The exact timestamps will differ because the cron rule controls when the job is enqueued.

Choosing cron, every, interval, at, or in

sidekiq-scheduler supports several timing models, but they do not behave identically. `cron` follows cron-style scheduling with seconds resolution. It is the clearest choice when execution should align with a wall-clock pattern, such as second zero of every minute or minute zero of every hour.

`every` triggers after a specified duration and accepts formats handled by `Fugit::Duration.parse`. The README gives values such as `45m`, `45 minutes`, `2 hours and 30 minutes`, and `1.5 hours`. Unlike `interval`, `every` does not define the next execution by counting from the last enqueue. Both forms count from when the Sidekiq process starts or restarts.

That restart behavior creates a real failure case. A schedule such as `every: '48h'` will not run if the Sidekiq process restarts more often than every 48 hours, because the duration never elapses between starts. The documented workaround is `every: ['48h', first_in: '0s']`, which can run immediately after a restart. The application then needs to determine whether the work is actually due.

`interval` starts its next execution after the configured interval has elapsed from the previous enqueue. For work that should remain spaced according to actual enqueue time, this is the more specific option. By contrast, `cron` is independent of prior completion and is tied to clock positions.

`at` and `in` are one-time schedules. An `at` value selects a point in time, while `in` represents a relative delay. These rules avoid the repeated timer state associated with recurring schedules. They also mean a missed process shutdown during the waiting period is different from a recurring rule that may run again later, although the README does not document persistence or missed-run recovery.

Runtime Reloading, Queue Filtering, and Schedule Controls

Schedules are static by default, but the `:dynamic` option can permit changes at runtime. When enabled, `:dynamic_every` controls how often the schedule is reloaded and defaults to five seconds. The README presents these as scheduler configuration settings in `sidekiq.yml`.

This design offers a practical alternative to redeploying an application after every schedule edit, but it also changes the operational model. Configuration becomes state that may change while workers are running. The README does not document validation behavior, update conflict handling, audit history, or what happens if the edited configuration is invalid. Those points require verification before production use.

Individual schedule entries have an `enabled` option and are enabled by default. Setting `enabled: false` disables an entry without removing its configuration. The overall `:enabled` scheduler setting defaults to `true`; setting it to `false` disables the scheduler. These are separate controls, so an overall scheduler enablement does not replace per-entry controls.

The `:rufus_scheduler_options` setting accepts custom options for Rufus Scheduler, including an example of `max_work_threads`. This gives access to scheduler behavior not exposed by the basic sidekiq-scheduler settings. The README does not enumerate all supported Rufus options, so it should not be treated as a complete option reference.

Dynamic reloads also interact with configuration distribution. If each Sidekiq process loads a different configuration or changes that configuration independently, their schedules may diverge. The README does not state a coordination model for multiple processes. Operators need to ensure that they point to the same intended schedule and understand the selected `:dynamic_every` interval before enabling this feature.

Maintenance, Compatibility, and MIT Licensing

The repository is not archived. Its last push was on 2026-09-08, which is recent relative to the listed releases and indicates current repository activity. The recent release history includes v6.0.2 on 2026-04-17, v6.0.1 on 2025-05-21, and v6.0.0 on 2025-05-12. The repository's current `master` branch is identified by the README as containing work for the v6 release, while older major versions are directed to separate stable branches.

That branch layout matters when planning an upgrade. An application cannot assume that every older configuration example applies unchanged to v6, and it cannot assume that the v5 branch and current branch have identical compatibility requirements. The README does not include a complete upgrade matrix, migration command, or a list of breaking changes for each release. `CHANGELOG.md` exists in the repository, but its contents are not included here, so no specific migration change should be inferred.

The project is distributed under the MIT license through `MIT-LICENSE`. This gives the project an open licensing model, but application owners still need to review that license text and account for the versions and dependencies used by their own distribution. This review is a licensing check, not legal advice.

The clearest upgrade cost visible in the documentation is integration effort: adapt worker declarations to the supported Sidekiq API, review renamed or deprecated interfaces, validate YAML timing syntax, and exercise queue and argument settings. The README specifically calls for `Sidekiq::Job` rather than the deprecated `Sidekiq::Worker` form for supported current Sidekiq usage.

Editorial conclusion

sidekiq-scheduler is appropriate for Ruby applications that already use Sidekiq and need schedules expressed in YAML, including recurring jobs, delayed one-time jobs, alternate queues, and runtime schedule reloads. It is a poor fit for deployments that do not run Sidekiq, require independently operated scheduling infrastructure, or need guarantees beyond those documented here. Before adoption, verify that your Sidekiq version uses `Sidekiq::Job`, that each cron expression uses the documented seconds-first format, and that your process restart policy is compatible with `every` and `interval`. The first project-specific check should be loading `config/sidekiq.yml` with the required `-r` file and confirming that the scheduler logs the expected worker and schedule.

Frequently asked questions

How do I install and run a first sidekiq-scheduler job?

Install the gem with `gem install sidekiq-scheduler`, define a class that includes `Sidekiq::Job`, configure its schedule in `config/sidekiq.yml`, and load the Ruby file with `sidekiq -r ./hello-scheduler.rb`.

Should sidekiq-scheduler cron expressions use five fields or six fields?

The README examples use a seconds-first cron string with six fields, such as `0 * * * * *`. It states that the project uses Fugit, which supports cron strings with up to six arguments.

What is the difference between every and interval in sidekiq-scheduler?

`every` schedules according to a duration counted from Sidekiq process startup or restart, while `interval` schedules the next execution after the interval has elapsed from the last job enqueue. Both therefore require attention to restart frequency.

Can sidekiq-scheduler pass keyword arguments and schedule metadata to a worker?

Yes, when documented options are configured. `keyword_argument: true` deconstructs a hash from `args`, while `include_metadata: true` adds a final metadata argument containing `:scheduled_at`.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. sidekiq-scheduler/sidekiq-scheduler on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sidekiq-scheduler-sidekiq-scheduler.svg)](https://hysenlabs.com/projects/sidekiq-scheduler-sidekiq-scheduler)

Was this useful?