Selama bertahun-tahun, cron jadi andalan buat scheduling needs di server. Backup cron, monitoring cron, cleanup cron — semua cron. Tapi cron punya kelemahan fundamental: gak punya built-in logging yang proper, gak ada notification kalau gagal, dan gak ada mekanisme untuk cek apakah task udah jalan.
Sejak insiden itu, migrate ke systemd timers. Dan perbedaannya luar biasa. Artikel ini bakal compare keduanya dengan data real dari production deployment di 5 server yang manage.
Cron: Still Works, Tapi...
Cron udah ada sejak 1975 — lebih tua dari banyak programmer yang baca artikel ini. Dia reliable untuk use case dasar: schedule task di waktu tertentu. Tapi ada beberapa fundamental limitations yang makin terasa di production modern:
# /etc/crontab example
0 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
*/5 * * * * www-data /usr/local/bin/health-check.sh
0 0 * * 0 root /usr/local/bin/cleanup.sh
Limitations cron yang gw alami di production:
- No logging standard: Cron cuma log ke syslog. Lo harus manually redirect output ke file sendiri. Dan kalau lo gak redirect, output-nya hilang. Pernah spend 2 jam debug cron job yang ternyata output-nya cuma ke /dev/null.
- No failure notification: Kalau cron job gagal, gak ada yang kasih tahu lo. Lo cuma tau kalau lo baca log manual — yang jarang dilakukan sampai ada masalah.
- No dependency management: Lo gak bisa bilang "jalankan task ini SETELAH service X ready." Cron cuma bisa schedule berdasarkan waktu, bukan state.
- No resource limits: Cron job bisa consume semua CPU/memory tanpa batas. Satu backup job yang runaway bisa bikin整个 server lambat.
- Timezone hell: Cron pake timezone server, bukan user. DST changes bisa bikin task jalan 2x atau 0x. Pernah kena DST bug yang bikin backup jalan 2 kali sehari selama seminggu.
- No concurrent run control: Kalau task sebelumnya belum selesai, cron bisa trigger lagi. Backup yang butuh 2 jam bisa overlap dengan backup berikutnya.
Systemd Timers: The Modern Alternative
Systemd timers adalah replacement modern untuk cron. Setiap timer punya service unit yang mendeskripsikan apa yang harus dilakukan, dan timer unit yang mendeskripsikan kapan harus dilakukan:
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily Backup Timer
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
# /etc/systemd/system/backup.service
[Unit]
Description=Daily System Backup
After=network.target postgresql.service
[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup.sh
StandardOutput=journal
StandardError=journal
# Resource limits (cron gak bisa ini!)
MemoryMax=512M
CPUQuota=50%
# Security hardening
ProtectSystem=strict
ProtectHome=true
NoNewPrivileges=true
PrivateTmp=true
ReadWritePaths=/var/backup
Yang langsung keliatan: systemd timer punya resource limits, security sandboxing, dan dependency management. Cron gak bisa ini. Dan semua output otomatis logged ke journal — gak perlu manual redirect.
Head-to-Head Comparison
| Feature | Cron | Systemd Timers |
|---|---|---|
| Logging | Syslog / manual redirect | journalctl — built-in, structured, queryable |
| Failure notification | Manual (script + email/Telegram) | Built-in (OnFailure=) |
| Resource limits | Tidak ada | MemoryMax, CPUQuota, etc |
| Security sandboxing | Tidak ada | ProtectSystem, NoNewPrivileges, etc |
| Dependency management | Tidak ada | After=, Requires=, Wants= |
| Missed run handling | Skip (silent failure) | Persistent=true (catch up on boot) |
| Concurrent run control | Perlu manual flock/lockfile | Type=oneshot gak overlap |
| Precision scheduling | Menit saja | Mikrosecond |
| Timezone handling | Server timezone | Explicit timezone support |
| Compatibility | Universal (semua distro) | Systemd distros only (2026: 95%+ distros) |
Practical Example: Backup Job Comparison
Lo lihat perbedaannya side by side:
Cron version:
# /etc/crontab
0 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Simple, tapi: kalau backup gagal? Lo cuma tau kalau lo baca log manual. Kalau server restart jam 2:59? Backup skip hari itu. Kalau backup jalan 5 jam dan mulai lagi jam 3? Overlap, bisa corrupt data.
Systemd version:
# backup.timer
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=300
# backup.service
[Unit]
After=postgresql.service
Requires=postgresql.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
OnFailure=backup-notify.service
MemoryMax=1G
TimeoutStartSec=3600
StandardOutput=journal
StandardError=journal
# backup-notify.service
[Unit]
Description=Backup Failure Notification
[Service]
Type=oneshot
ExecStart=/usr/local/bin/notify-telegram.sh "BACKUP FAILED on $(hostname)"
Fitur kunci yang di-enable:
- Persistent=true: Kalau timer missed (server restart), task dijalankan saat boot berikutnya. Gak ada yang skip.
- OnFailure=: Kalau backup gagal, notifikasi otomatis dikirim ke Telegram. Gak perlu baca log.
- After=postgresql.service: Backup cuma mulai setelah Postgres ready. Gak ada race condition.
- MemoryMax=1G: Backup gak boleh consume lebih dari 1GB RAM. Kalau lebih, OOM kill — tapi gak impact server.
- TimeoutStartSec=3600: Max 1 jam. Kalau lebih lama, kemungkinan ada masalah.
- journalctl logging: Semua output otomatis logged dengan structured format. Queryable dengan filter.
Monotonic Scheduling: Timer Tanpa Wall Clock
Selain OnCalendar (wall clock), systemd timers support monotonic timestamps — scheduling berdasarkan waktu berlalu, bukan waktu absolut. Ini powerful untuk use case yang butuh interval tetap:
# Run 5 menit setelah boot, lalu setiap 30 menit
[Timer]
OnBootSec=5min
OnUnitActiveSec=30min
# Run 1 jam setelah service sebelumnya selesai
[Timer]
OnUnitInactiveSec=1h
Kenapa ini penting? Karena OnCalendar bisa "miss" kalau server restart di antara schedule. Tapi OnUnitActiveSec selalu trigger relatif terhadap waktu terakhir task jalan — jadi gak ada yang terlewat. Ini analogi yang sama dengan setInterval vs setTimeout di JavaScript.
Gw pake pola ini untuk monitoring check: setiap 30 menit, cek apakah service masih hidup. Kalau pakai OnCalendar, jam 3:00 bisa kelewat. Dengan OnUnitActiveSec=30min, interval tetap 30 menit regardless of schedule disruptions.
Monitoring dan Observability
Ini yang paling gw appreciate dari systemd timers — observability yang built-in. Satu command untuk lihat semua scheduled tasks dan status-nya:
# Lihat semua timers dan status
systemctl list-timers --all
# Output:
# NEXT LEFT LAST PASSED UNIT
# Mon 2026-07-05 03:00:00 6h left Sun 2026-07-04 03:00:00 18h ago backup.timer
# Mon 2026-07-05 00:00:00 3h left Sat 2026-07-04 00:00:00 21h ago cleanup.timer
# Lihat log dari backup terakhir
journalctl -u backup.service --since "24 hours ago" --no-pager
# Cek apakah timer aktif
systemctl status backup.timer
# Lihat semua runs dalam sebulan
journalctl -u backup.service --since "1 month ago" | grep -E "Started|Failed|Completed"
# Lihat duration setiap run
journalctl -u backup.service --since "1 week ago" -o json | python3 -c "import sys,json; [print(json.loads(l)['MESSAGE']) for l in sys.stdin if 'MESSAGE' in json.loads(l)]"
Dengan cron, lo harus manually parse /var/log/syslog, setup custom logging, dan bikin script untuk analyze logs. Dengan systemd, semua sudah terstruktur dan queryable dalam satu command.
Error Handling Pattern
Salah satu kekuatan systemd timers adalah ability untuk define error handling secara declarative. Lo bisa define different handling untuk different failure levels:
# monitoring.service — health check
[Unit]
Description=System Health Check
[Service]
Type=oneshot
ExecStart=/usr/local/bin/health-check.sh
SuccessExitStatus=0 1
# Exit code 1 = warning, bukan error
# monitoring-failure.service — critical failure handler
[Unit]
Description=Monitoring Failure Handler
[Service]
Type=oneshot
ExecStart=/usr/local/bin/critical-alert.sh "Health check failed!"
Pattern ini memungkinkan lo define berbagai level of failure: info, warning, critical. Setiap level bisa punya different handling. Cron gak bisa ini — semua failure diperlakukan sama (diam-diam hilang).
Migration Checklist
| Step | Action | Verification |
|---|---|---|
| 1 | Buat .timer dan .service files | systemd-analyze verify backup.service |
| 2 | Enable dan start timer | systemctl enable --now backup.timer |
| 3 | Test run manual | systemctl start backup.service |
| 4 | Verify logging | journalctl -u backup.service |
| 5 | Disable cron job | crontab -e, komentar baris |
| 6 | Monitor 1 minggu | systemctl list-timers + journalctl |
Proses migration biasanya cuma butuh 15-30 menit per task. Return on investment-nya terasa dalam minggu pertama — lo langsung bisa lihat status semua scheduled tasks dalam satu command.
Real-World Migration: Study Kasus
Gw migrate 5 server dari cron ke systemd timers dalam 2 minggu. Hasilnya:
| Server | Jumlah Cron Jobs | Migration Time | Issues Found |
|---|---|---|---|
| Web Production | 8 | 45 menit | 2 jobs silently failing |
| Database Server | 5 | 30 menit | 1 job overlap (backup) |
| CI/CD Runner | 12 | 60 menit | 3 jobs missing logging |
| Monitoring | 6 | 25 menit | None — clean migration |
| Dev Server | 4 | 15 menit | 1 job using wrong user |
Yang sering terjadi di lapangan: cron jobs gagal tanpa ada yang tau — kadang backup job udah gagal berminggu-minggu tanpa terdeteksi. Tanpa monitoring yang proper, data production bisa hilang permanent.
Kapan Tetap Pakai Cron?
Jujur, cron masih relevan untuk beberapa use case, dan gw gak mau sounding seperti sales systemd yang bilang "ganti semua ke systemd timers sekarang juga!" — karena realitanya lebih nuanced dan situationally-dependent dari itu:
- User crontab: Systemd timers butuh root access. Kalau lo cuma mau schedule task sebagai user biasa,
crontab -emasih lebih gampang. - Legacy systems: Server yang gak pakai systemd (Alpine with OpenRC, runit-based distros). Tapi di 2026, ini makin jarang.
- Truly trivial tasks: "Backup file ini sekali sehari" — cron cukup. Jangan over-engineer.
- Portable scripts: Kalau script lo harus jalan di berbagai distro (termasuk yang gak pakai systemd), cron lebih universal.
Tapi untuk production server yang butuh observability, reliability, dan security — systemd timers adalah pilihan yang lebih baik. Migrasi dari cron ke systemd timer biasanya cuma butuh 30 menit per task, dan ROI-nya terasa langsung dalam minggu pertama — terutama kalau lo nemu cron jobs yang udah silently fail selama berminggu-minggu tanpa ada yang sadari sama sekali.
Untuk scheduling pipeline data analytics, cek artikel tentang arsitektur LTAP. Untuk security task scheduling, baca tentang backup strategy 3-2-1. Dan kalau lo mau monitor semua scheduled tasks dari satu dashboard, pertimbangkan integrasi dengan ELK atau Loki untuk centralized logging.
💬 Komentar (0)
Belum ada komentar. Jadilah yang pertama! 💬