| 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.
jobs:
- name: "System Health Check"
minute: "*/5"
hour: "*"
weekday: "*"
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