# 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 ```bash # 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](https://git.keks.cloud/kekskurse/scron/releases): ```bash # 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`). ```yaml 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 ```yaml # 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 ```yaml 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 ```yaml jobs: - name: "Weekday Task" minute: "0" hour: "9" weekday: "1-5" # Monday to Friday command: "weekday-task.sh" ``` ## Notification Configuration ### Gotify Configuration ```yaml 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 ```yaml 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: ```yaml 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 ```yaml 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 ```yaml 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 ```yaml 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: ```json {"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