Cron Jobs in S-UI: How Automated Background Tasks Keep Your Panel Running

S-UI uses the robfig/cron library to execute five automated background jobs that handle statistics collection, client expiration, database maintenance, and core process monitoring.

The S-UI panel (alireza0/s-ui) implements a robust background task system to ensure continuous service availability and data integrity. These cron jobs in S-UI operate automatically once the application starts, requiring no manual intervention for routine maintenance. All scheduled tasks are orchestrated through the CronJob struct in cronjob/cronJob.go, which initializes the scheduler with the server's time zone and configured traffic retention settings.

How the Cron Scheduler Initializes

At application startup, the app.Start function instantiates a CronJob and invokes its Start method. This method accepts a *time.Location for timezone-aware scheduling and an integer trafficAge that determines how many days of traffic statistics to retain.

The CronJob struct maintains a *cron.Cron instance from the robfig/cron library. When Start executes, it creates the scheduler with seconds precision and the provided location:

// cronjob/cronJob.go – simplified view
func (c *CronJob) Start(loc *time.Location, trafficAge int) error {
    c.cron = cron.New(cron.WithLocation(loc), cron.WithSeconds())
    c.cron.Start()
    go func() {
        c.cron.AddJob("@every 10s", NewStatsJob(trafficAge > 0))
        c.cron.AddJob("@every 1m", NewDepleteJob())
        if trafficAge > 0 {
            c.cron.AddJob("@daily", NewDelStatsJob(trafficAge))
        }
        c.cron.AddJob("@every 5s", NewCheckCoreJob())
        c.cron.AddJob("@every 10m", NewWALCheckpointJob())
    }()
    return nil
}

The method registers all jobs within a goroutine and enables graceful shutdown via the Stop method, which halts the cron scheduler cleanly.

The Five Automated Background Jobs

S-UI runs five distinct jobs on different schedules to maintain system health. Each job is implemented as a separate file in the cronjob/ directory.

StatsJob – Real-Time Statistics Collection (@every 10s)

The StatsJob runs every 10 seconds to capture system metrics. Located in cronjob/statsJob.go, it calls StatsService.SaveStats to persist connection counters. If the trafficAge parameter is greater than zero, the job also records detailed per-client traffic data for historical analysis; otherwise, it saves only current connection statistics without persistent traffic logging.

DepleteJob – Client Expiration Management (@every 1m)

Running every minute, the DepleteJob (cronjob/depleteJob.go) enforces subscription time limits. It invokes ClientService.DepleteClients to disable clients whose expiration dates have passed, then triggers InboundService.RestartInbounds to restart only the affected inbound listeners, applying changes without disrupting active connections on unchanged ports.

DelStatsJob – Data Retention Enforcement (@daily)

The DelStatsJob (cronjob/delStatsJob.go) executes daily at midnight, but only when trafficAge is configured greater than zero. This job calls StatsService.DelOldStats to remove statistics records older than the specified retention period, preventing unbounded database growth and maintaining query performance.

CheckCoreJob – Process Resilience (@every 5s)

To ensure continuous proxy service availability, the CheckCoreJob (cronjob/checkCoreJob.go) runs every five seconds. It verifies that the core V2Ray process is active and invokes ConfigService.StartCore to restart the process if it has crashed or stopped unexpectedly.

WALCheckpointJob – Database Optimization (@every 10m)

Every ten minutes, the WALCheckpointJob (cronjob/WALCheckpointJob.go) executes PRAGMA wal_checkpoint(FULL) on the SQLite database. This write-ahead log checkpoint prevents the WAL file from growing excessively large, which could otherwise degrade performance or consume excessive disk space during high-traffic periods.

Practical Usage Examples

While the cron system starts automatically with the application, understanding the underlying API enables custom integrations and testing scenarios.

Starting the Cron System Manually

To initialize the scheduler programmatically with a 30-day traffic retention period:

package main

import (
    "time"

    "github.com/alireza0/s-ui/cronjob"
)

func main() {
    // Example: use the server's local time zone and keep traffic for 30 days
    loc, _ := time.LoadLocation("Local")
    cron := cronjob.NewCronJob()
    _ = cron.Start(loc, 30) // error handling omitted for brevity
    // The scheduler now runs in the background
    select {} // block forever (or integrate with the rest of the app)
}

Manually Invoking a Job for Testing

You can execute any job synchronously for debugging or one-time maintenance:

package main

import (
    "github.com/alireza0/s-ui/cronjob"
)

func main() {
    // Run the statistics job once, without persisting traffic data
    job := cronjob.NewStatsJob(false)
    job.Run() // logs any error internally
}

Adjusting Traffic Retention Policies

The trafficAge parameter controls two behaviors simultaneously:

  • When trafficAge > 0: StatsJob saves detailed traffic data, and DelStatsJob is scheduled to run daily.
  • When trafficAge == 0: Traffic storage is disabled, and the daily cleanup job is omitted entirely.
cron.Start(loc, 0) // disables traffic collection and old-stats cleanup

Summary

  • S-UI implements five automated cron jobs using the robfig/cron library, initialized in cronjob/cronJob.go.
  • StatsJob collects metrics every 10 seconds, with optional persistent traffic logging based on the trafficAge setting.
  • DepleteJob disables expired clients and restarts affected inbounds every minute.
  • DelStatsJob runs daily to purge old statistics when retention is enabled.
  • CheckCoreJob ensures the V2Ray process remains active by checking every 5 seconds.
  • WALCheckpointJob prevents SQLite WAL file bloat by running PRAGMA wal_checkpoint(FULL) every 10 minutes.

Frequently Asked Questions

What library does S-UI use for scheduling cron jobs?

S-UI uses the robfig/cron library with seconds-level precision and timezone support. The scheduler is configured in cronjob/cronJob.go with cron.WithSeconds() and cron.WithLocation() to ensure accurate task execution based on the server's local time.

How often does S-UI verify that the V2Ray core is running?

The CheckCoreJob runs every 5 seconds (@every 5s) to verify process health. If the core process has stopped, it immediately invokes ConfigService.StartCore to restart the service, ensuring minimal downtime for proxy connections.

Can I disable traffic data collection to save disk space?

Yes. When initializing the cron system, set the trafficAge parameter to 0. This disables the persistent storage of traffic statistics in StatsJob and prevents the DelStatsJob from being registered, eliminating both the storage overhead and the daily cleanup routine.

Where are the individual job implementations located in the repository?

Each cron job resides in its own file within the cronjob/ directory: statsJob.go for statistics collection, depleteJob.go for client expiration, delStatsJob.go for data retention, checkCoreJob.go for process monitoring, and WALCheckpointJob.go for database maintenance.

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 →