FeaturesBlogDocs GitHub Get Started

flashQ Cron Jobs: Complete Guide to Scheduled Tasks

Scheduled tasks are essential for any production application. Whether you need to send daily reports, clean up old data, sync external APIs, or run periodic health checks, flashQ's cron jobs have you covered.

Understanding Cron Syntax

flashQ uses a 6-field cron expression that includes seconds:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ second (0-59)
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ minute (0-59)
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€ hour (0-23)
β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€ day of month (1-31)
β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€ month (1-12)
β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€ day of week (0-6, Sunday=0)
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
* * * * * *

Common Patterns

ExpressionDescription
0 * * * * *Every minute
0 0 * * * *Every hour
0 0 9 * * *Daily at 9 AM
0 30 9 * * 1-5Weekdays at 9:30 AM
0 0 0 * * 0Weekly on Sunday midnight
0 0 0 1 * *Monthly on the 1st
0 */15 * * * *Every 15 minutes
0 0 */2 * * *Every 2 hours

Creating Cron Jobs

import { Queue } from 'flashq';

const queue = new Queue('scheduled-tasks');

// Daily report at 9 AM
await queue.addCron('daily-report', {
  queue: 'scheduled-tasks',
  schedule: '0 0 9 * * *',
  data: {
    type: 'daily-report',
    recipients: ['team@company.com'],
  },
});

// Cleanup every Sunday at midnight
await queue.addCron('weekly-cleanup', {
  queue: 'scheduled-tasks',
  schedule: '0 0 0 * * 0',
  data: {
    type: 'cleanup',
    olderThanDays: 30,
  },
});

// Health check every 5 minutes
await queue.addCron('health-check', {
  queue: 'scheduled-tasks',
  schedule: '0 */5 * * * *',
  data: {
    type: 'health-check',
    endpoints: ['/api/health', '/api/db'],
  },
});

Managing Cron Jobs

// List all cron jobs
const crons = await queue.listCrons();
console.log(crons);
// [
//   { name: 'daily-report', schedule: '0 0 9 * * *', ... },
//   { name: 'weekly-cleanup', schedule: '0 0 0 * * 0', ... },
// ]

// Delete a cron job
await queue.deleteCron('health-check');

// Update a cron job (delete + recreate)
await queue.deleteCron('daily-report');
await queue.addCron('daily-report', {
  queue: 'scheduled-tasks',
  schedule: '0 0 8 * * *', // Changed to 8 AM
  data: { type: 'daily-report' },
});

Real-World Use Cases

1. Daily Analytics Report

await queue.addCron('analytics-report', {
  queue: 'reports',
  schedule: '0 0 6 * * *', // 6 AM daily
  data: {
    type: 'analytics',
    metrics: ['users', 'revenue', 'conversions'],
    format: 'pdf',
  },
});

// Worker
new Worker('reports', async (job) => {
  const { metrics, format } = job.data;

  // Generate report
  const report = await generateAnalyticsReport(metrics);
  const pdf = await convertToPDF(report);

  // Send via email
  await sendEmail({
    to: 'executives@company.com',
    subject: `Daily Analytics - ${new Date().toDateString()}`,
    attachments: [pdf],
  });
});

2. Database Cleanup

await queue.addCron('db-cleanup', {
  queue: 'maintenance',
  schedule: '0 0 3 * * *', // 3 AM daily (low traffic)
  data: {
    tasks: [
      { table: 'sessions', olderThan: '7 days' },
      { table: 'logs', olderThan: '30 days' },
      { table: 'temp_files', olderThan: '1 day' },
    ],
  },
});

3. API Sync

await queue.addCron('sync-stripe', {
  queue: 'integrations',
  schedule: '0 */30 * * * *', // Every 30 minutes
  data: {
    provider: 'stripe',
    syncTypes: ['subscriptions', 'invoices'],
  },
});

4. Cache Warming

await queue.addCron('warm-cache', {
  queue: 'cache',
  schedule: '0 55 * * * *', // 5 min before each hour
  data: {
    endpoints: [
      '/api/products',
      '/api/categories',
      '/api/homepage',
    ],
  },
});
πŸ’‘ Timezone Handling

Cron jobs run in the server's timezone (typically UTC). For user-facing schedules, store the user's timezone and convert when creating the cron expression.

Best Practices

1. Idempotent Jobs

Design cron jobs to be idempotentβ€”running them twice shouldn't cause issues:

// Good: Check before processing
async function processDaily() {
  const lastRun = await db.settings.get('lastDailyRun');
  const today = new Date().toDateString();

  if (lastRun === today) {
    console.log('Already ran today, skipping');
    return;
  }

  // Process...
  await db.settings.set('lastDailyRun', today);
}

2. Overlap Prevention

Prevent jobs from overlapping if they take longer than expected:

new Worker('maintenance', async (job) => {
  const lockKey = `lock:${job.name}`;

  // Try to acquire lock
  const acquired = await redis.set(lockKey, '1', 'NX', 'EX', 3600);

  if (!acquired) {
    console.log('Job already running, skipping');
    return;
  }

  try {
    // Process job...
  } finally {
    await redis.del(lockKey);
  }
});

3. Error Alerting

worker.on('failed', async (job, error) => {
  if (job.name.startsWith('cron:')) {
    await sendSlackAlert({
      channel: '#ops-alerts',
      message: `Cron job failed: ${job.name}\nError: ${error.message}`,
    });
  }
});

Conclusion

flashQ cron jobs provide a reliable way to schedule recurring tasks. Key takeaways:

  • Use 6-field cron syntax (includes seconds)
  • Design idempotent jobs
  • Implement overlap prevention for long-running tasks
  • Set up alerting for failures

Start Scheduling

Add cron jobs to your application in minutes.

Get Started β†’
ESC