From godmode
Orchestrates scheduled tasks, cron jobs, and recurring background jobs with BullMQ, Celery, Sidekiq, node-cron, APScheduler. Covers cron syntax, distributed scheduling, and overlap protection.
How this skill is triggered — by the user, by Claude, or both
Slash command
/godmode:cronThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- User invokes `/godmode:cron`
/godmode:cronsetInterval or setTimeout loops that need conversion to proper scheduled jobsEvaluate what needs to run, how often, and under what constraints:
SCHEDULING REQUIREMENTS ASSESSMENT:
| Dimension | Value |
| Task type | <cleanup | report | sync | alert |
| | billing | digest | health check> |
| Frequency | <seconds | minutes | hourly | |
CRON EXPRESSION SYNTAX:
| Field | Values | Special chars |
| Minute | 0-59 | * , - / |
| Hour | 0-23 | * , - / |
| Day of month | 1-31 | * , - / ? L W |
Common patterns:
and 7 = Sunday) — check your library
SCHEDULER TECHNOLOGY SELECTION:
| Technology | Language | Backend | Distributed| Persistence| Ops cost |
|--|--|--|--|--|--|
| node-cron | Node.js | In-proc | No | None | Minimal |
| | Simple cron | (memory) | (single) | (restart | |
| | schedules | | | loses) | |
| | | | | | |
| BullMQ | Node.js | Redis | Yes | Redis | Low |
...
Design the scheduling topology, job registry, and execution flow:
SCHEDULE ARCHITECTURE:
| Scheduler Job Registry Executors |
| --------- ------------ --------- |
| +-- daily-digest -------------- Worker Pool A (2) |
| Cron Engine ------+-- cleanup-expired ----------- Worker Pool B (3) |
import { Queue, Worker, QueueEvents } from 'bullmq';
import Redis from 'ioredis';
const connection = new Redis({
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
from celery import Celery
from celery.schedules import crontab, solar
from datetime import timedelta
app = Celery('scheduler', broker='redis://localhost:6379/0', backend='redis://localhost:6379/1')
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.redis import RedisJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
from apscheduler.triggers.cron import CronTrigger
import pytz
Sidekiq-Cron (Ruby): Sidekiq::Cron::Job.load_from_hash with cron expression, class, and queue.
Hangfire (.NET): RecurringJob.AddOrUpdate with cron expression, SQL Server or Redis storage.
Quartz (Java): @Configuration with JobDetail bean and CronTrigger schedule.
Every scheduled job MUST safely run more than once for the same logical execution window:
IDEMPOTENCY STRATEGIES FOR SCHEDULED JOBS:
| Strategy | Use case |
| Date-based key | "digest:2025-03-15" — one per day |
| Window-based key | "sync:2025-03-15T10:00Z" — one |
| | per 15-min window |
Principle: derive the idempotency key from the SCHEDULE, not the job ID.
- The system re-creates the job on restart with a new ID
...
// Idempotent wrapper for scheduled jobs
class ScheduledJobRunner {
constructor(private redis: Redis) {}
async runOnce(
jobName: string,
Prevent multiple scheduler instances from firing the same job simultaneously:
DISTRIBUTED LOCKING STRATEGIES:
| Method | Backend | Pros | Cons |
| Redis SETNX + EX | Redis | Fast, atomic acquire | Not CP-safe |
| Redlock | Redis | Multi-node consensus | Controversial |
| DB advisory lock | Postgres| No extra infra | DB-coupled |
| ZooKeeper/etcd | ZK/etcd | CP-safe, reliable | Ops overhead |
class DistributedSchedulerLock {
constructor(private redis: Redis) {}
async acquireLeader(schedulerId: string, ttl: number = 30): Promise<boolean> {
// Only one scheduler instance becomes leader
const acquired = await this.redis.set(
import hashlib
def pg_advisory_lock_for_job(conn, job_name: str) -> bool:
"""Acquire a PostgreSQL advisory lock for a scheduled job.
Returns True if lock acquired, False if another process holds it."""
# Convert job name to a stable int64 for PG advisory lock
Track schedule health and detect missed or failing runs:
CRON JOB MONITORING:
| Metric | Current | Alert | Status |
| Jobs scheduled | 8 | — | OK |
| Last run: daily-digest | 09:00 | miss > 1h| OK |
| Last run: cleanup | 06:00 | miss > 7h| OK |
// Scheduled job health monitor
class CronJobMonitor {
constructor(private redis: Redis, private alerter: Alerter) {}
async recordRun(jobName: string, result: {
status: 'success' | 'failure';
Handle scheduled jobs that exhaust retries:
SCHEDULED JOB DLQ DESIGN:
| DLQ for Scheduled Jobs |
| Queue: scheduled-jobs-dlq |
| Retention: 30 days |
| Alert: Any entry (scheduled jobs should not fail) |
Design priority-aware scheduling and dependent job pipelines:
SCHEDULED JOB PRIORITIES:
| Priority | Schedule | Job | SLA |
| P0 | */5 * * * * | Health check | < 30s |
| P1 | */15 * * * * | Inventory sync | < 2m |
| P1 | 0 9 * * * | Daily digest | < 5m |
JOB CHAINING (dependent execution):
| Pipeline: "end-of-day" |
// BullMQ Flow (parent-child dependencies)
import { FlowProducer } from 'bullmq';
const flowProducer = new FlowProducer({ connection });
// End-of-day pipeline — child jobs run first, parent last
Prevent scheduled jobs from overwhelming downstream services:
RATE-LIMITED SCHEDULING:
| Scenario | Strategy |
| API with 100 req/min | Token bucket limiter on worker |
| Email provider 500/hr | BullMQ limiter: 500 per 3600s |
| DB batch writes | Chunk + delay between batches |
// Scheduled job that processes in rate-limited batches
async function runDailyDigest() {
const users = await db.users.findMany({
where: { digestEnabled: true, lastDigestBefore: today() },
});
Handle timezone-aware scheduling correctly:
TIMEZONE HANDLING:
| Rule |
| 1. Store all schedules in UTC internally |
| 2. Convert to user timezone for display only |
| 3. Use IANA timezone names (America/New_York), never |
Choose the right persistence layer:
SCHEDULER PERSISTENCE COMPARISON:
| Aspect | Redis-backed | DB-backed |
| Speed | Sub-ms operations | 1-10ms queries |
| Durability | RDB/AOF (config) | Full ACID |
| Crash recovery | May lose last | No data loss |
Use Redis-backed (BullMQ, Sidekiq-Cron) when:
- Need complex queries on job history
1. Save schedule configuration as `config/schedules/registry.ts`
2. Save scheduler setup as `config/schedules/scheduler.ts`
3. Save idempotency helpers as `lib/scheduled-job-runner.ts`
4. Save monitoring as `lib/cron-monitor.ts`
5. Commit: "cron: <scheduler> — <N> jobs, <frequency range>, <lock strategy>"
6. If new scheduler: "Scheduled jobs configured. <N> jobs registered. Deploy and monitor."
7. If fixing failures: "Idempotency and locking added. Missed-schedule alerting enabled."
8. If migrating: "Migrated from <old> to <new>. All schedules verified."
Never ask to continue. Loop autonomously until done.
# Validate cron expressions and test jobs
npx cron-validate "0 9 * * 1-5"
npm run test:cron -- --timeout 30000
redis-cli KEYS "bull:*:repeat:*" | head -10
IF job duration > 80% of interval: increase interval or optimize job. WHEN missed runs > 0 in 24h: alert and investigate. IF retry count > 3: move to dead letter queue.
| Flag | Description |
|---|---|
| (none) | Full scheduled task design workflow |
--tech <name> | Target specific scheduler (bullmq, celery, sidekiq, apscheduler, hangfire, quartz, node-cron) |
--diagnose | Diagnose missed or failing scheduled jobs |
KEEP if: improvement verified. DISCARD if: regression or no change. Revert discards immediately.
Stop when: target reached, budget exhausted, or >5 consecutive discards.
npx claudepluginhub arbazkhan971/godmodeGuides cron job scheduler setup, configuration, and best practices for backend systems. Generates production-ready cron configurations.
Builds production-grade scheduled jobs with cron syntax, overlap prevention, monitoring, and structured logging. Activates when users mention cron jobs, scheduled tasks, or recurring jobs.
Designs task scheduling systems: job queues, cron at scale, delayed/recurring tasks, worker pools with leasing, priorities, and exactly-once execution.