# How to Configure Scheduled Maintenance Jobs with Sidekiq-Cron in Maybe Finance

> Learn how to configure scheduled maintenance jobs with sidekiq-cron in Maybe Finance. Define cron expressions, route jobs, and set up catch-up windows for efficient automation.

- Repository: [Maybe/maybe](https://github.com/maybe-finance/maybe)
- Tags: how-to-guide
- Published: 2026-03-07

---

**Maybe Finance configures scheduled maintenance jobs using the sidekiq-cron gem by defining cron expressions in [`config/schedule.yml`](https://github.com/maybe-finance/maybe/blob/main/config/schedule.yml), routing jobs through a dedicated `scheduled` queue configured in [`config/sidekiq.yml`](https://github.com/maybe-finance/maybe/blob/main/config/sidekiq.yml), and initializing the system with a 10-minute catch-up window in [`config/initializers/sidekiq.rb`](https://github.com/maybe-finance/maybe/blob/main/config/initializers/sidekiq.rb).**

The open-source personal finance application Maybe Finance relies on periodic background tasks to synchronize market data, clean up stale records, and perform other maintenance operations. Understanding how these scheduled maintenance jobs are configured with Sidekiq-Cron provides insight into the robust, declarative background processing architecture that keeps the application data fresh and accurate.

## Understanding the Sidekiq-Cron Architecture

Maybe implements scheduled jobs through three coordinated configuration layers. The architecture separates schedule definitions from queue routing and runtime initialization, allowing for clear, maintainable cron management.

The three core components are:

- **Cron definition file** ([`config/schedule.yml`](https://github.com/maybe-finance/maybe/blob/main/config/schedule.yml)): Declares job names, cron expressions, and worker class mappings
- **Queue configuration** ([`config/sidekiq.yml`](https://github.com/maybe-finance/maybe/blob/main/config/sidekiq.yml)): Defines the `scheduled` queue that sidekiq-cron uses for recurring jobs
- **Runtime initializer** ([`config/initializers/sidekiq.rb`](https://github.com/maybe-finance/maybe/blob/main/config/initializers/sidekiq.rb)): Boots the cron system and configures job loading behavior

## Step 1: Defining Cron Schedules in schedule.yml

The [`config/schedule.yml`](https://github.com/maybe-finance/maybe/blob/main/config/schedule.yml) file serves as the central registry for all recurring maintenance tasks. Each entry maps a unique job name to a Sidekiq worker class, cron schedule, and target queue.

### Structure of the Cron Definition File

Entries follow a YAML structure specifying the `cron` expression, `class` name, and `queue` assignment:

```yaml

# config/schedule.yml

daily_market_sync:
  cron: "0 22 * * 1-5"   # 5 PM EST / 6 PM EDT, Monday through Friday

  class: "MarketDataSyncWorker"
  queue: scheduled

stale_sync_cleanup:
  cron: "0 * * * *"      # Every hour on the hour

  class: "StaleSyncCleanerWorker"
  queue: scheduled

```

The `cron` field accepts standard cron syntax, while the `class` field references the worker implementation located in `app/workers/` (for example, [`app/workers/market_data_sync_worker.rb`](https://github.com/maybe-finance/maybe/blob/main/app/workers/market_data_sync_worker.rb)).

## Step 2: Configuring the Scheduled Queue in sidekiq.yml

Maybe routes all cron-triggered jobs through a dedicated queue to separate scheduled maintenance from user-triggered background tasks. This isolation prevents maintenance workloads from blocking critical user-facing jobs.

### Queue Weight and Priority

The [`config/sidekiq.yml`](https://github.com/maybe-finance/maybe/blob/main/config/sidekiq.yml) file declares the `scheduled` queue with a weight of 10, giving it moderate priority relative to other queues:

```yaml

# config/sidekiq.yml

:queues:
  - [default, 5]
  - [mailers, 1]
  - [scheduled, 10]

```

The weight value determines how often Sidekiq checks this queue for work relative to others. A weight of 10 ensures timely execution of maintenance tasks without starving the default queue.

## Step 3: Initializing Sidekiq-Cron in the Rails Initializer

The runtime configuration lives in [`config/initializers/sidekiq.rb`](https://github.com/maybe-finance/maybe/blob/main/config/initializers/sidekiq.rb), where Maybe boots the sidekiq-cron system and defines how it handles schedule loading and job catch-up behavior.

### Loading the Schedule File

The initializer invokes `Sidekiq::Cron.configure` to load the YAML schedule and apply global settings:

```ruby

# config/initializers/sidekiq.rb

Sidekiq::Cron.configure do |config|
  # Load the schedule file

  config.load_from_yaml("#{Rails.root}/config/schedule.yml")
  
  # 10-minute catch-up window (see comment on line 14)

  config.catch_up_window = 10.minutes
end

```

### Configuring the Catch-Up Window

The `catch_up_window` parameter set to `10.minutes` provides a grace period for missed executions. If a cron tick occurs while the Sidekiq process is restarting or deploying, the job will still be enqueued when the new process starts, provided the downtime does not exceed ten minutes.

## How Scheduled Maintenance Jobs Execute

When the Rails process starts, the initializer runs `Sidekiq::Cron.configure`, which performs the following sequence:

1. **Parses** [`config/schedule.yml`](https://github.com/maybe-finance/maybe/blob/main/config/schedule.yml) and creates a `Sidekiq::Cron::Job` instance for each entry
2. **Maps** each cron job to its specified Sidekiq worker class (e.g., `MarketDataSyncWorker`)
3. **Enqueues** jobs to the `scheduled` queue defined in [`config/sidekiq.yml`](https://github.com/maybe-finance/maybe/blob/main/config/sidekiq.yml) when the cron expression triggers
4. **Applies** the 10-minute catch-up logic to ensure jobs are not lost during deployments

The worker classes themselves reside in `app/workers/` and implement the actual maintenance logic, such as syncing market data or cleaning stale records.

## Summary

Maybe Finance configures scheduled maintenance jobs with Sidekiq-Cron through a three-layer declarative setup:

- **Schedule definitions** live in [`config/schedule.yml`](https://github.com/maybe-finance/maybe/blob/main/config/schedule.yml), mapping cron expressions to worker classes
- **Queue routing** is handled in [`config/sidekiq.yml`](https://github.com/maybe-finance/maybe/blob/main/config/sidekiq.yml) via a dedicated `scheduled` queue with weight 10
- **Runtime initialization** occurs in [`config/initializers/sidekiq.rb`](https://github.com/maybe-finance/maybe/blob/main/config/initializers/sidekiq.rb), loading the schedule and configuring a 10-minute catch-up window to prevent missed jobs during deployments

This architecture separates scheduling logic from execution logic, ensuring reliable, maintainable background processing for critical financial data synchronization.

## Frequently Asked Questions

### What is the purpose of the catch-up window in Sidekiq-Cron?

The catch-up window ensures that scheduled jobs are not lost during application deployments or process restarts. Maybe Finance sets this to 10 minutes in [`config/initializers/sidekiq.rb`](https://github.com/maybe-finance/maybe/blob/main/config/initializers/sidekiq.rb), meaning if a cron tick occurs while Sidekiq is temporarily offline, the job will still be enqueued when the process restarts, provided the downtime does not exceed the configured window.

### How do you add a new scheduled maintenance job to Maybe Finance?

To add a new job, first create a Sidekiq worker class in `app/workers/` (for example, [`app/workers/new_maintenance_worker.rb`](https://github.com/maybe-finance/maybe/blob/main/app/workers/new_maintenance_worker.rb)). Then add an entry to [`config/schedule.yml`](https://github.com/maybe-finance/maybe/blob/main/config/schedule.yml) specifying the `cron` expression, the `class` name, and the `queue` (typically `scheduled`). Finally, restart the Sidekiq process to load the new schedule via the initializer in [`config/initializers/sidekiq.rb`](https://github.com/maybe-finance/maybe/blob/main/config/initializers/sidekiq.rb).

### What happens if a scheduled job fails in Sidekiq-Cron?

When a scheduled job fails, Sidekiq's standard retry mechanism applies according to the worker class configuration. The job remains in the `scheduled` queue (or moves to the retry queue) and Sidekiq attempts to reprocess it based on the retry count and backoff strategy defined in the worker. The cron schedule continues to enqueue new instances independently of previous failures.

### Where are the worker classes for scheduled jobs defined in Maybe Finance?

Worker classes reside in the `app/workers/` directory. For example, the `MarketDataSyncWorker` referenced in [`config/schedule.yml`](https://github.com/maybe-finance/maybe/blob/main/config/schedule.yml) is defined in [`app/workers/market_data_sync_worker.rb`](https://github.com/maybe-finance/maybe/blob/main/app/workers/market_data_sync_worker.rb). These classes inherit from Sidekiq's worker base class and implement the `perform` method containing the actual maintenance logic executed on schedule.