No description
Find a file
kekskurse fc3549d722
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
fix: remove debug println
2025-08-06 19:04:49 +02:00
scripts fix: dont remove service file from script as well 2025-07-31 23:41:17 +02:00
vendor feat: smtp notification 2025-07-31 20:11:30 +02:00
.gitignore ci: goreleaser 2025-07-31 03:23:35 +02:00
.goreleaser.yml docs: change goreleaser info 2025-07-31 22:37:16 +02:00
.woodpecker.yml ci: gitea token secret 2025-07-31 03:36:05 +02:00
config.go fix: remove debug println 2025-08-06 19:04:49 +02:00
config.yml.example feat: add timezone 2025-08-06 18:55:22 +02:00
config_test.go feat: add timezone 2025-08-06 18:55:22 +02:00
error.go init 2025-07-31 03:01:56 +02:00
go.mod feat: smtp notification 2025-07-31 20:11:30 +02:00
go.sum feat: smtp notification 2025-07-31 20:11:30 +02:00
gotify.go feat: gotify notification 2025-07-31 18:43:03 +02:00
jobResult.go feat: gotify notification 2025-07-31 18:43:03 +02:00
main.go chore: Logging level to info 2025-08-06 18:22:25 +02:00
README.md feat: add timezone 2025-08-06 18:55:22 +02:00
smtp.go feat: smtp notification 2025-07-31 20:11:30 +02:00
time.go init 2025-07-31 03:01:56 +02:00
timer_test.go test: timer test 2025-08-06 18:50:15 +02:00

SCRON

A lightweight, efficient cron-like scheduler written in Go that executes shell commands at specified intervals with precise timing, comprehensive logging, and flexible notification support.

Features

  • 🕐 Flexible Scheduling: Advanced cron-like time patterns with minute-level precision
  • 🔄 Dynamic Configuration: Automatic config reloading without restart
  • 📊 Structured Logging: JSON-formatted logs with zerolog for easy parsing
  • 🔔 Multi-Channel Notifications: Support for Gotify and SMTP notifications
  • Concurrent Execution: Jobs run in parallel for optimal performance
  • 🛡️ Robust Error Handling: Comprehensive error tracking with exit codes
  • 📝 Output Capture: Combined stdout/stderr capture for debugging

Installation

From Source

# Clone the repository
git clone https://github.com/yourusername/scron.git
cd scron

# Build the binary
go build -o scron ./

# Run
./scron

Debian Package

Download the latest .deb package from the releases page:

# Install package
sudo dpkg -i scron_X.X.X_linux_amd64.deb

Configuration file location: /etc/scron/config.yml

Configuration

Create a config.yml file in the same directory as the binary (or /etc/scron/ for package installations):

Basic Configuration

Optionally, you can specify the weekday field (0=Sunday, 1=Monday, ..., 6=Saturday) to restrict jobs to specific days of the week.

You can also optionally specify the timezone field to set the timezone for each job. Default is UTC. You can use any timezone supported by Go (e.g., Europe/Berlin).

jobs:
  - name: "System Health Check"
    minute: "*/5"
    hour: "*"
    weekday: "*"
    timezone: "Europe/Berlin"
    command: "curl -f http://localhost:8080/health || exit 1"
  
  - name: "Daily Backup"
    minute: "0"
    hour: "2"
    weekday: "*"
    command: "/usr/local/bin/backup.sh"

Advanced Configuration with Notifications

# Notification configurations
notification:
  - name: default
    success:
      gotify:
        url: "https://gotify.example.com/message?token=YOUR_TOKEN"
      smtp:
        host: "smtp.gmail.com"
        port: 587
        username: "your-email@gmail.com"
        password: "your-app-password"
        from: "scron@example.com"
        to: "admin@example.com"
        use_ssl: true
    error:
      gotify:
        url: "https://gotify.example.com/message?token=YOUR_CRITICAL_TOKEN"
      smtp:
        host: "smtp.gmail.com"
        port: 587
        username: "your-email@gmail.com"
        password: "your-app-password"
        from: "scron-alerts@example.com"
        to: "oncall@example.com"
        use_ssl: true

  - name: critical-only
    error:
      gotify:
        url: "https://gotify.example.com/message?token=YOUR_CRITICAL_TOKEN"

# Job definitions
jobs:
  - name: "Database Backup"
    minute: "0"
    hour: "3"
    weekday: "*"
    command: "pg_dump mydb > /backup/mydb_$(date +%Y%m%d).sql"
    notification: default
  
  - name: "Critical Service Monitor"
    minute: "*/1"
    hour: "*"
    weekday: "*"
    command: "systemctl is-active nginx || exit 1"
    notification: critical-only

Time Pattern Syntax (minute, hour, and optional weekday)

SCRON supports flexible cron-like time patterns for minutes (0-59), hours (0-23), and optional weekdays (0-6). 0 is Sunday, 1 is Monday, and so on:

Pattern Description Example
* Every minute/hour minute: "*" - every minute
n Specific value hour: "14" - at 2 PM
*/n Every n intervals minute: "*/15" - every 15 minutes
n,m Multiple values hour: "9,12,17" - at 9 AM, noon, and 5 PM
n-m Range (inclusive) hour: "9-17" - 9 AM to 5 PM
n-m/s Range with step minute: "10-50/10" - at 10, 20, 30, 40, 50
n-m,x-y Multiple ranges hour: "0-6,20-23" - night hours

Pattern Examples

jobs:
  # Every minute
  - name: "Heartbeat"
    minute: "*"
    hour: "*"
    weekday: "*"
    command: "echo 'alive'"

  # Every 5 minutes
  - name: "Frequent Check"
    minute: "*/5"
    hour: "*"
    weekday: "*"
    command: "check-service.sh"

  # At specific minutes
  - name: "Quarter Hours"
    minute: "0,15,30,45"
    hour: "*"
    weekday: "*"
    command: "quarter-hour-task.sh"

  # Business hours only (9 AM - 5 PM)
  - name: "Business Task"
    minute: "0"
    hour: "9-17"
    weekday: "*"
    command: "business-process.sh"

  # Complex schedule
  - name: "Complex Task"
    minute: "5-55/10"  # At 5, 15, 25, 35, 45, 55
    hour: "8-18/2"     # Every 2 hours from 8 AM to 6 PM
    weekday: "*"
    command: "complex-task.sh"

Weekday Field Example

jobs:
  - name: "Weekday Task"
    minute: "0"
    hour: "9"
    weekday: "1-5"  # Monday to Friday
    command: "weekday-task.sh"

Notification Configuration

Gotify Configuration

notification:
  - name: gotify-alerts
    success:
      gotify:
        url: "https://gotify.example.com/message?token=YOUR_TOKEN"
    error:
      gotify:
        url: "https://gotify.example.com/message?token=YOUR_PRIORITY_TOKEN"

Gotify notifications include:

  • Success messages with low priority (-1)
  • Error messages with high priority (10)
  • Job name, command, and output in the message body

SMTP Configuration

notification:
  - name: email-alerts
    success:
      smtp:
        host: "smtp.office365.com"
        port: 587
        username: "notifications@company.com"
        password: "secure-password"
        from: "scron@company.com"
        to: "devops@company.com"
        use_ssl: true
    error:
      smtp:
        host: "smtp.office365.com"
        port: 587
        username: "alerts@company.com"
        password: "secure-password"
        from: "scron-alerts@company.com"
        to: "oncall@company.com"
        use_ssl: true

Multiple Notification Channels

You can configure both Gotify and SMTP in the same notification configuration - both will be used:

notification:
  - name: multi-channel
    error:
      gotify:
        url: "https://gotify.example.com/message?token=TOKEN"
      smtp:
        host: "smtp.gmail.com"
        port: 587
        username: "alerts@example.com"
        password: "app-password"
        from: "scron@example.com"
        to: "team@example.com"
        use_ssl: true

Advanced Examples

Database Maintenance

jobs:
  - name: "PostgreSQL Vacuum"
    minute: "0"
    hour: "4"
    command: "psql -U postgres -d mydb -c 'VACUUM ANALYZE;'"
    notification: database-alerts

  - name: "MySQL Backup"
    minute: "30"
    hour: "3"
    command: |
      mysqldump --all-databases > /backup/mysql_$(date +%Y%m%d_%H%M%S).sql && \
      find /backup -name "mysql_*.sql" -mtime +7 -delete
    notification: backup-alerts

System Monitoring

jobs:
  - name: "Disk Space Check"
    minute: "*/30"
    hour: "*"
    command: |
      USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
      if [ $USAGE -gt 80 ]; then
        echo "WARNING: Disk usage is at ${USAGE}%"
        exit 1
      fi
    notification: critical-alerts

  - name: "Memory Check"
    minute: "*/10"
    hour: "*"
    command: |
      FREE_MEM=$(free -m | awk 'NR==2 {print $4}')
      if [ $FREE_MEM -lt 500 ]; then
        echo "Low memory: ${FREE_MEM}MB free"
        exit 1
      fi
    notification: system-alerts

Log Rotation

jobs:
  - name: "Rotate Application Logs"
    minute: "0"
    hour: "0"
    command: |
      find /var/log/myapp -name "*.log" -size +100M -exec gzip {} \; && \
      find /var/log/myapp -name "*.gz" -mtime +30 -delete

Logging

SCRON uses structured JSON logging with zerolog. Logs include:

  • Job execution start/completion
  • Command output (stdout and stderr)
  • Exit codes
  • Execution errors
  • Configuration reload events
  • Notification delivery status

Example log output:

{"level":"info","time":"2024-01-15T10:00:00Z","message":"Executing job","job":"Database Backup","command":"pg_dump mydb > backup.sql"}
{"level":"info","time":"2024-01-15T10:00:05Z","message":"Job completed","job":"Database Backup","exit_code":0}

Error Handling

SCRON provides comprehensive error handling:

  • Configuration Errors: Invalid YAML, missing required fields
  • Time Pattern Errors: Invalid cron patterns with detailed error messages
  • Execution Errors: Command failures, non-zero exit codes
  • Notification Errors: Failed delivery attempts are logged but don't stop job execution

Best Practices

  1. Use Absolute Paths: Always use absolute paths in commands to avoid PATH issues
  2. Set Proper Exit Codes: Ensure your scripts exit with non-zero codes on failure
  3. Test Commands: Test your commands manually before adding to configuration
  4. Monitor Logs: Regularly check SCRON logs for execution issues
  5. Use Notifications Wisely: Configure different notification channels for different severity levels
  6. Keep Commands Simple: For complex tasks, use shell scripts instead of inline commands