Files
Microsoft-Rewards-Bot/src/scheduler/README.md

7.0 KiB

Internal Scheduler

Overview

The Internal Scheduler is a cross-platform scheduling system built into the bot. It automatically runs the bot daily at a specified time - no external cron setup required, no Task Scheduler configuration needed.

Features

Simple time format - Just specify "09:00" for 9 AM
Automatic timezone detection - Uses your computer/server timezone automatically
Cross-platform - Works on Windows, Linux, and macOS
Zero external configuration - No cron or Task Scheduler setup required
Overlap protection - Prevents concurrent runs
Automatic retry - Retries failed runs with exponential backoff
Clean shutdown - Gracefully stops on CTRL+C or SIGTERM

Quick Start

1. Enable Scheduling

Edit src/config.jsonc:

{
  "scheduling": {
    "enabled": true,
    "time": "09:00"  // Daily at 9:00 AM (your local time)
  }
}

2. Run the Bot

npm start

The bot will:

  • Start the internal scheduler
  • Detect your timezone automatically
  • Keep the process alive
  • Execute automatically daily at the specified time
  • Log each scheduled run

3. Stop the Bot

Press CTRL+C to stop the scheduler and exit cleanly.

Time Format Examples

Time Description
"09:00" Daily at 9:00 AM
"21:30" Daily at 9:30 PM
"00:00" Daily at midnight
"12:00" Daily at noon
"06:15" Daily at 6:15 AM

Note: Always use 24-hour format (HH:MM). The scheduler automatically uses your system's timezone.

Configuration Options

scheduling.enabled

  • Type: boolean
  • Default: false
  • Description: Enable/disable automatic scheduling

scheduling.time

  • Type: string
  • Format: "HH:MM" (24-hour format)
  • Default: "09:00"
  • Description: Daily execution time in your local timezone
  • Examples: "09:00", "21:30", "00:00"

Legacy scheduling.cron.schedule (deprecated)

  • Type: string (cron expression)
  • Description: Advanced cron format (e.g., "0 9 * * *")
  • Note: Supported for backwards compatibility. Use time instead for simplicity.

Timezone Detection

The scheduler automatically detects your timezone using your computer/server's system settings:

  • Windows: Uses Windows timezone settings
  • Linux/Mac: Uses system timezone (usually from /etc/localtime)
  • Docker: Uses container timezone (set via TZ environment variable)

You don't need to configure timezone manually! The bot logs the detected timezone on startup:

✓ Internal scheduler started
  Daily run time: 09:00
  Timezone: America/New_York
  Next run: Thu, Jan 18, 2024, 09:00 AM

How It Works

  1. Initialization

    • Bot reads config.scheduling
    • Detects your timezone automatically
    • Creates scheduler for daily execution
    • Validates time format
  2. Execution

    • Scheduler waits until next scheduled time
    • Triggers bot execution (initialize() + run())
    • Logs start/completion/errors
    • Calculates next run time
  3. Error Handling

    • Failed runs are retried (using config.crashRecovery settings)
    • Overlap protection prevents concurrent runs
    • Errors are logged but don't stop the scheduler
  4. Shutdown

    • SIGINT/SIGTERM signals stop the scheduler
    • Current task completes before exit
    • Cleanup handlers run normally

Advantages Over OS Schedulers

Feature Internal Scheduler OS Scheduler
Setup complexity Simple Manual config
Time format Simple (09:00) Complex cron
Windows support Auto Task Scheduler setup
Linux support Auto ⚠️ crontab config
Timezone handling Automatic Manual
Centralized logs Yes Separate logs
Dashboard integration Possible No
Process management ⚠️ Must stay alive Cron handles

Docker Users

Docker users can continue using cron if preferred (see docker/ directory). The internal scheduler is optional and doesn't interfere with Docker cron setup.

Docker Timezone Setup:

# docker/compose.yaml
environment:
  - TZ=America/New_York  # Set your timezone
  - RUN_ON_START=true

Troubleshooting

Scheduler doesn't start

  • Check scheduling.enabled is true
  • Verify time is in HH:MM format (e.g., "09:00")
  • Look for errors in console output

Wrong timezone detected

  • Check your system timezone settings
  • For Docker, set TZ environment variable
  • Verify in logs: "Timezone: YOUR_TIMEZONE"

Runs don't trigger at expected time

  • Verify time format is 24-hour (e.g., "21:00" not "9:00 PM")
  • Check system clock is correct
  • Wait for the next scheduled time (check logs for "Next run")

Process exits unexpectedly

  • Check jobState.autoResetOnComplete is true (for scheduled runs)
  • Review crash logs
  • Ensure no SIGTERM/SIGINT signals from system

Advanced: Cron Format (Legacy)

For users who need complex schedules (e.g., multiple times per day, specific weekdays), you can use the legacy cron format:

{
  "scheduling": {
    "enabled": true,
    "cron": {
      "schedule": "0 9,21 * * *"  // Daily at 9 AM and 9 PM
    }
  }
}

Cron Expression Examples:

Schedule Cron Expression Description
Every day at 9 AM 0 9 * * * Once daily
Every 6 hours 0 */6 * * * 4 times a day
Twice daily (9 AM, 9 PM) 0 9,21 * * * Morning & evening
Weekdays at 8 AM 0 8 * * 1-5 Monday-Friday only
Every 30 minutes */30 * * * * 48 times a day

Note: Use crontab.guru to create and validate cron expressions.

API Reference

InternalScheduler.start()

Starts the scheduler. Returns true if successful.

InternalScheduler.stop()

Stops the scheduler gracefully.

InternalScheduler.isActive()

Returns true if scheduler is running.

InternalScheduler.getStatus()

Returns scheduler status object:

{
  active: boolean
  isRunning: boolean
  lastRun: string | null
  nextRun: string
}

InternalScheduler.triggerNow()

Manually trigger an immediate run (useful for dashboard).

  • Implementation: src/scheduler/InternalScheduler.ts
  • Integration: src/index.ts (main function)
  • Config: src/config.jsonc
  • Interface: src/interface/Config.ts (ConfigScheduling)

Example: Complete Setup

// src/config.jsonc
{
  "scheduling": {
    "enabled": true,
    "time": "09:00"  // Daily at 9 AM (automatic timezone)
  },
  "jobState": {
    "enabled": true,
    "autoResetOnComplete": true  // Reset state after each scheduled run
  },
  "crashRecovery": {
    "enabled": true,
    "maxRetries": 3  // Retry failed runs up to 3 times
  }
}

Then run:

npm start

You'll see:

✓ Internal scheduler started
  Daily run time: 09:00
  Timezone: America/New_York
  Next run: Thu, Jan 18, 2024, 09:00 AM
Bot is ready and waiting for scheduled execution...