Skip to main content

Scheduler CLI Commands

The scheduler module provides CLI commands for managing scheduled jobs from the command line.

Available Commands

scheduler list

List all scheduled jobs with optional filtering.

yarn saasframe scheduler list [options]

Options:

OptionDescriptionExample
--tenant <id>Filter by tenant ID--tenant tenant-123
--scope <type>Filter by scope type--scope system
--enabled <bool>Filter by enabled status--enabled true
--module <id>Filter by source module--module currencies

Examples:

# List all schedules
yarn saasframe scheduler list

# List only system-scoped schedules
yarn saasframe scheduler list --scope system

# List enabled schedules for a tenant
yarn saasframe scheduler list --tenant tenant-123 --enabled true

# List schedules created by a module
yarn saasframe scheduler list --module currencies

Output:

┌────────────────────────────────────┬─────────────────────┬──────────┬──────────┬────────────┬────────────┬─────────┬────────┐
│ ID │ Name │ Type │ Schedule │ Target │ Next Run │ Enabled │ Source │
├────────────────────────────────────┼─────────────────────┼──────────┼──────────┼────────────┼────────────┼─────────┼────────┤
│ currencies:fetch-rates:org-123 │ Fetch Currency Rates│ Cron │ 0 */6 ** │ Queue │ 2024-01-27 │ true │ module │
│ │ │ │ * * │ currency...│ 12:00:00 │ │ │
├────────────────────────────────────┼─────────────────────┼──────────┼──────────┼────────────┼────────────┼─────────┼────────┤
│ reports:daily:tenant-456 │ Daily Sales Report │ Cron │ 0 6 * * *│ Command │ 2024-01-28 │ true │ user │
│ │ │ │ │ reports... │ 06:00:00 │ │ │
└────────────────────────────────────┴─────────────────────┴──────────┴──────────┴────────────┴────────────┴─────────┴────────┘

Found 2 schedules

scheduler status

Show the current status of the scheduler system.

yarn saasframe scheduler status

Output (Local Strategy):

Scheduler Status
================

Strategy: local
Status: running
Poll Interval: 30000ms

Active Schedules: 5
- System: 2
- Organization: 1
- Tenant: 2

Next Upcoming Runs:
- reports:daily:tenant-456 at 2024-01-28 06:00:00 (America/New_York)
- currencies:fetch-rates:org-123 at 2024-01-27 12:00:00 (UTC)
- cleanup:weekly:system at 2024-01-28 02:00:00 (UTC)

Queue Strategy: local
Database: connected

Output (Async Strategy):

Scheduler Status
================

Strategy: async
Status: synced

Active Schedules: 5
- System: 2
- Organization: 1
- Tenant: 2

BullMQ Status:
- Redis: connected
- Repeatable Jobs: 5
- Execution Queue: scheduler-execution
- Pending Jobs: 0
- Active Jobs: 2
- Failed Jobs: 1

Next Upcoming Runs:
- reports:daily:tenant-456 at 2024-01-28 06:00:00 (America/New_York)
- currencies:fetch-rates:org-123 at 2024-01-27 12:00:00 (UTC)
- cleanup:weekly:system at 2024-01-28 02:00:00 (UTC)

Worker Status:
- Workers running: 3
- Total concurrency: 15

Queue Strategy: async
Redis: connected
Database: connected

scheduler run

Manually execute a scheduled job immediately.

yarn saasframe scheduler run <schedule-id>

Arguments:

ArgumentDescriptionRequired
schedule-idThe UUID or ID of the schedule to runYes

Examples:

# Run by UUID
yarn saasframe scheduler run 123e4567-e89b-12d3-a456-426614174000

# Run by custom ID
yarn saasframe scheduler run currencies:fetch-rates:org-123

Output (Success):

Running schedule: currencies:fetch-rates:org-123
Schedule: Fetch Currency Rates
Type: Cron (0 */6 * * *)
Target: Queue (currency-rates)

Execution started...
Job enqueued: bullmq-job-12345
Status: completed
Duration: 2.3s

Result:
{
"fetched": 42,
"updated": 40,
"failed": 2
}

Output (Failure):

Running schedule: reports:daily:tenant-456
Schedule: Daily Sales Report
Type: Cron (0 6 * * *)
Target: Command (reports.generate-daily)

Execution started...
Error: Command failed after 5.2s

Error details:
{
"message": "Database connection timeout",
"code": "ETIMEDOUT"
}

Exit Codes:

  • 0 - Success
  • 1 - Schedule not found
  • 2 - Schedule is disabled
  • 3 - Execution failed
  • 4 - Invalid schedule ID

scheduler start

Start the scheduler engine.

tip

Behavior differs based on QUEUE_STRATEGY:

  • Local: Starts polling engine (keeps running)
  • Async: One-time sync with BullMQ (exits after sync)
yarn saasframe scheduler start

Local Strategy Output:

Starting scheduler in LOCAL mode...

Configuration:
- Poll Interval: 30000ms
- Lock Strategy: in-process (single instance only)
- Execution: Direct (queue/command)

Database connected
Lock acquired: scheduler-poller

Active schedules loaded: 5
- System: 2
- Organization: 1
- Tenant: 2

Polling started. Press Ctrl+C to stop gracefully...

[10:00:00] Poll cycle 1: checked 5 schedules, executed 0
[10:00:30] Poll cycle 2: checked 5 schedules, executed 1
- reports:daily:tenant-456 (completed in 2.1s)
[10:01:00] Poll cycle 3: checked 5 schedules, executed 0
...

^C
Shutting down gracefully...
Lock released
Scheduler stopped

Async Strategy Output:

Starting scheduler in ASYNC mode...

Configuration:
- Redis: redis://localhost:6379
- Queue: scheduler-execution
- Execution: BullMQ workers

Database connected
Redis connected

Syncing schedules with BullMQ...

Processing schedules:
✓ currencies:fetch-rates:org-123 (synced)
✓ reports:daily:tenant-456 (synced)
✓ cleanup:weekly:system (synced)
✓ backup:nightly:tenant-789 (synced)
- old-schedule:removed (removed orphan)

Sync complete:
- Synced: 4
- Removed: 1
- Errors: 0

Scheduler synced successfully.

Next steps:
1. Start workers: yarn saasframe worker:start
2. Monitor queue: yarn saasframe queue status scheduler-execution

Exiting...

Options:

OptionDescriptionDefault
--poll-interval <ms>Poll interval in milliseconds (local mode)30000
--verboseEnable verbose loggingfalse

Examples:

# Start with default settings
yarn saasframe scheduler start

# Start with custom poll interval (local mode)
yarn saasframe scheduler start --poll-interval 60000

# Start with verbose logging
yarn saasframe scheduler start --verbose

Exit Codes:

  • 0 - Success (async: sync complete, local: clean shutdown)
  • 1 - Database connection failed
  • 2 - Redis connection failed (async mode)
  • 3 - Lock acquisition failed (local mode)
  • 130 - Interrupted by user (Ctrl+C, local mode)

Common Workflows

Development Setup

# 1. Check scheduler status
yarn saasframe scheduler status

# 2. List existing schedules
yarn saasframe scheduler list

# 3. Start scheduler (keeps running)
yarn saasframe scheduler start

# In another terminal, test a schedule
yarn saasframe scheduler run test:my-schedule

Production Setup

# 1. Ensure environment is configured
export QUEUE_STRATEGY=async
export REDIS_URL=redis://localhost:6379

# 2. Check status
yarn saasframe scheduler status

# 3. Sync schedules (one-time)
yarn saasframe scheduler start

# 4. Start workers (separate process)
yarn saasframe worker:start

# 5. Monitor execution
yarn saasframe queue status scheduler-execution

Debugging Failed Schedules

# 1. List all schedules
yarn saasframe scheduler list

# 2. Check status
yarn saasframe scheduler status

# 3. Run schedule manually to see error
yarn saasframe scheduler run <schedule-id>

# 4. Check logs
tail -f logs/scheduler.log

# 5. Check queue status (async mode)
yarn saasframe queue status scheduler-execution

# 6. View failed jobs (async mode)
yarn saasframe queue failed scheduler-execution

Monitoring Production

# Check scheduler health
yarn saasframe scheduler status

# View active schedules
yarn saasframe scheduler list --enabled true

# Check for failed executions (async mode)
yarn saasframe queue failed scheduler-execution

# View execution history (async mode)
yarn saasframe queue history scheduler-execution --limit 20

# Check worker health (async mode)
yarn saasframe worker:status

Environment Variables

The scheduler CLI respects these environment variables:

VariableDescriptionDefault
QUEUE_STRATEGYExecution strategy: local or asynclocal
REDIS_URLRedis connection URL (async mode)redis://localhost:6379
SCHEDULER_POLL_INTERVAL_MSPoll interval in milliseconds (local mode)30000
DATABASE_URLPostgreSQL connection URLRequired
LOG_LEVELLogging level: debug, info, warn, errorinfo

Exit Codes Reference

CodeMeaningContext
0SuccessAll commands
1General errorAll commands
2Configuration errorscheduler start
3Execution errorscheduler run
4Not foundscheduler run
130User interrupt (Ctrl+C)scheduler start (local)

Integration with Other CLI Tools

Worker Management

# Start all workers (includes scheduler execution worker)
yarn saasframe worker:start

# Start only scheduler worker
yarn saasframe worker:start --queue scheduler-execution

# Check worker status
yarn saasframe worker:status

Queue Management

# View scheduler execution queue
yarn saasframe queue status scheduler-execution

# View pending jobs
yarn saasframe queue pending scheduler-execution

# View failed jobs
yarn saasframe queue failed scheduler-execution

# Retry failed jobs
yarn saasframe queue retry scheduler-execution <job-id>

# Clean old jobs
yarn saasframe queue clean scheduler-execution --grace 86400

Database Management

# View scheduler tables
yarn saasframe db:schema --table scheduled_jobs

# Run migrations
yarn saasframe db:migrate

# Generate new migration (after entity changes)
yarn saasframe db:generate

Troubleshooting

"Schedule not found"

# List all schedules to verify ID
yarn saasframe scheduler list

# Check if schedule was soft-deleted
yarn saasframe db:query "SELECT * FROM scheduled_jobs WHERE id = '<id>'"

"Lock acquisition failed"

# Check if another scheduler instance is running
ps aux | grep "scheduler start"

# Release stuck lock (PostgreSQL)
yarn saasframe db:query "SELECT pg_advisory_unlock_all()"

"Redis connection failed"

# Check Redis status
redis-cli ping

# Verify REDIS_URL
echo $REDIS_URL

# Test connection
redis-cli -u $REDIS_URL ping

"No workers running"

# Check worker status
yarn saasframe worker:status

# Start workers
yarn saasframe worker:start

# Check worker logs
tail -f logs/worker.log

Best Practices

  1. Use scripts for automation - Add scheduler commands to package.json scripts
  2. Monitor in production - Set up cron jobs to check scheduler status
  3. Log everything - Use --verbose flag when debugging
  4. Test manually first - Use scheduler run before enabling new schedules
  5. Graceful shutdowns - Always use Ctrl+C instead of kill -9
  6. Check status regularly - Run scheduler status to catch issues early
  7. Filter list output - Use filters to reduce noise in large deployments
  8. Sync after changes - Re-run scheduler start after modifying schedules (async mode)

See Also