| scripts | ||
| vendor | ||
| .gitignore | ||
| .goreleaser.yml | ||
| .woodpecker.yml | ||
| config.go | ||
| config.yml.example | ||
| config_test.go | ||
| error.go | ||
| go.mod | ||
| go.sum | ||
| gotify.go | ||
| jobResult.go | ||
| main.go | ||
| README.md | ||
| smtp.go | ||
| time.go | ||
| timer_test.go | ||
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
- Use Absolute Paths: Always use absolute paths in commands to avoid PATH issues
- Set Proper Exit Codes: Ensure your scripts exit with non-zero codes on failure
- Test Commands: Test your commands manually before adding to configuration
- Monitor Logs: Regularly check SCRON logs for execution issues
- Use Notifications Wisely: Configure different notification channels for different severity levels
- Keep Commands Simple: For complex tasks, use shell scripts instead of inline commands