How CasaOS Uses the Periodic Task Scheduler (cron) for Background Jobs

CasaOS leverages the robfig/cron library with second-level precision to execute recurring background tasks such as hardware status broadcasting and file maintenance, initializing schedulers in main/main.go and managing them through graceful lifecycle hooks.

CasaOS, the open-source home cloud system developed by IceWhaleTech, implements a periodic task scheduler using the robfig/cron library to manage background jobs efficiently. This architecture allows the system to execute recurring tasks—such as real-time hardware monitoring and file maintenance—without blocking the main application thread, ensuring responsive performance while handling critical housekeeping operations.

Scheduler Architecture and Initialization

The system adopts a decentralized approach where both the main application and individual packages can instantiate their own cron schedulers. In main/main.go, the core entry point creates a global scheduler instance that persists for the application's lifetime.

Global Instance with Second-Level Precision

Lines 121-127 of main/main.go establish the primary scheduler using cron.New(cron.WithSeconds()), enabling second-level granularity critical for real-time monitoring. This configuration distinguishes CasaOS's implementation from standard minute-level cron systems.

crontab := cron.New(cron.WithSeconds())

The scheduler is started after task registration and includes a deferred shutdown hook: defer crontab.Stop(). This ensures that when the main process exits, all background goroutines terminate cleanly without resource leaks.

Registering Background Jobs

Jobs are registered using either the @every duration syntax or standard cron expressions, with callbacks defined as standard Go functions. CasaOS uses both patterns depending on the required granularity.

Hardware Status Broadcasting

The primary periodic job runs every 5 seconds to push system telemetry to the frontend. In main/main.go, this is registered as:

if _, err := crontab.AddFunc("@every 5s", route.SendAllHardwareStatusBySocket); err != nil {
    logger.Error("add crontab error", zap.Error(err))
}

The callback function SendAllHardwareStatusBySocket resides in route/periodical.go (lines 25-74). This function gathers CPU, memory, network, and temperature data from the system service, constructs a payload, and broadcasts it via the notification bus using the channel casaos:system:utilization.

File Maintenance Tasks

In route/v1/file.go (lines 988-1000), a separate scheduler instance handles file-related cleanup operations. This implementation uses a quartz-style cron expression to execute every 30 seconds:

crontab := cron.New(cron.WithSeconds())
spec := "*/30 * * * * ?" // every 30 seconds
crontab.AddFunc(spec, task)
crontab.Start()

This pattern demonstrates how individual packages can manage their own lifecycle without interfering with the global scheduler.

Lifecycle Management and Graceful Shutdown

Proper resource management is critical for long-running daemons. CasaOS handles this by:

  1. Initializing the scheduler with cron.New(cron.WithSeconds())
  2. Registering jobs immediately after creation
  3. Starting the scheduler with crontab.Start()
  4. Deferring shutdown with defer crontab.Stop() to guarantee cleanup on process exit

This pattern prevents orphan goroutines and ensures that all pending jobs complete or receive termination signals before the application closes.

Practical Code Examples

Initializing a Custom Scheduler

The following pattern mirrors CasaOS's approach for creating a second-precision scheduler with error handling:

package main

import (
    "github.com/robfig/cron/v3"
    "log"
)

func main() {
    // Create a second-precision scheduler
    scheduler := cron.New(cron.WithSeconds())

    // Register a job that runs every 10 seconds
    _, err := scheduler.AddFunc("@every 10s", func() {
        log.Println("Running periodic cleanup")
        // …insert cleanup logic here…
    })
    if err != nil {
        log.Fatalf("failed to add cron job: %v", err)
    }

    // Start the scheduler
    scheduler.Start()
    defer scheduler.Stop()

    // Block forever (or replace with your server’s run loop)
    select {}
}

Hardware Status Function Implementation

The actual task implementation from route/periodical.go shows how to integrate system monitoring with the notification system:

func SendAllHardwareStatusBySocket() {
    netList := service.MyService.System().GetNetInfo()
    // …collect network, CPU, memory, temperature…
    body := map[string]interface{}{
        "sys_mem": memInfo,
        "sys_cpu": cpuData,
        "sys_net": newNet,
    }
    // Push to front-end via notification bus
    service.MyService.Notify().SendNotify("casaos:system:utilization", body)
}

Summary

  • CasaOS uses the robfig/cron/v3 library with second-level precision for all background job scheduling
  • The global scheduler is initialized in main/main.go using cron.New(cron.WithSeconds()) to enable sub-minute intervals
  • Hardware status updates run every 5 seconds via SendAllHardwareStatusBySocket in route/periodical.go
  • File cleanup tasks use quartz expressions like */30 * * * * ? in route/v1/file.go with independent scheduler instances
  • Graceful shutdown is guaranteed via defer crontab.Stop() to prevent resource leaks

Frequently Asked Questions

What cron library does CasaOS use?

CasaOS uses the github.com/robfig/cron/v3 library, which provides standard cron expression parsing along with extended features like second-level precision and the @every duration syntax. This dependency is declared in the project's go.mod file.

How frequently does CasaOS broadcast hardware status updates?

According to the source code in main/main.go, the system broadcasts hardware status every 5 seconds using the @every 5s descriptor. This triggers the SendAllHardwareStatusBySocket function defined in route/periodical.go, which collects CPU, memory, network, and temperature metrics.

How does CasaOS prevent resource leaks from background goroutines?

The application ensures clean shutdown by calling defer crontab.Stop() immediately after starting the scheduler. This deferred function signals all running cron jobs to terminate gracefully when the main process exits, preventing goroutine leaks and ensuring proper cleanup of system resources.

Can cron jobs run at sub-minute intervals in CasaOS?

Yes, by initializing the scheduler with cron.WithSeconds(), CasaOS supports sub-minute intervals that would be impossible with standard minute-level cron implementations. This allows expressions like @every 5s for hardware monitoring or */30 * * * * ? for file cleanup tasks running every 30 seconds.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →