Về blog

Cron vs systemd timer: Bạn nên dùng cái nào?

11 tháng 9, 2026

Trên một distro hiện đại, dùng systemd timer cho mọi thứ bạn sở hữu và giữ cron cho job user một dòng cùng những server bạn không tự dựng. Timer log mọi lần chạy vào journal, có thể chạy bù những lịch bị lỡ khi máy tắt, và phụ thuộc vào cùng loại unit file như mọi thứ khác trên hệ thống. Cron thắng về gọn gàng — một dòng crontab -e hơn hai unit file — và nó vẫn là scheduler duy nhất được đảm bảo tồn tại trên container tối giản và những máy Unix lạ. Cái bẫy: cron hỏng trong im lặng. Nếu job của bạn lỗi lúc 3 giờ sáng, cron gửi thư vào một mailbox local chẳng ai đọc, trong khi timer cho bạn journalctl -u mytimer.service với đầy đủ output. Bên dưới: khác biệt thật sự, cách test mỗi bên, vì sao một timer có thể không kích hoạt, và một bảng quyết định.

cron và systemd timer khác nhau ở điểm nào?

Cron là một daemon đọc một bảng các dòng — năm trường thời gian và một lệnh — và chạy mỗi lệnh khi đồng hồ hệ thống khớp. Đó là toàn bộ mô hình. Nó không có khái niệm job như một đối tượng: không unit, không status, không dependency, không bản ghi log riêng.

Một systemd timer là unit file (foo.timer) kích hoạt một unit file khác (foo.service) khi lịch của nó khớp. Job là một đối tượng hạng nhất với start, status, logs, và theo dõi thất bại như bất kỳ service nào khác. Lập lịch hoặc theo calendar (kiểu cron) hoặc theo monotonic (OnBootSec=15min, thứ mà việc đổi đồng hồ hệ thống không làm nhầm được).

Hệ quả thực tế:

  • Log: timer log stdout/stderr vào journal theo từng unit; cron tối đa là gửi thư cho user local.
  • Lần chạy bị lỡ: timer có Persistent=true chạy một lần khi boot nếu lịch bị lỡ; cron chỉ việc bỏ qua.
  • Dependency: timer có thể chờ network-online.target hoặc mount point; cron bắt bạn tự viết logic retry trong script.
  • Cú pháp: cron là một dòng; timer là hai file. Đó là toàn bộ cái giá của việc chuyển.

Cú pháp lịch nào dễ hơn — crontab hay OnCalendar?

Năm trường của cron là chuẩn nhỏ gọn đang ngồi sẵn: */15 * * * * là mỗi 15 phút, và đa số admin đọc được cả khi ngủ. OnCalendar= của systemd dài dòng hơn nhưng biểu đạt mạnh hơn hẳn, và systemd-analyze calendar nói cho bạn biết các lần chạy kế tiếp trước khi bạn chốt — cron không có dry-run tương đương.

# Cron: mỗi ngày lúc 03:30
30 3 * * * /usr/local/bin/backup.sh

# systemd: cùng lịch đó, kiểm chứng được trước khi bạn lưu
systemd-analyze calendar "*-*-* 03:30:00"
# -> Lần chạy kế: Fri 2026-09-11 03:30:00 ...

OnCalendar xử lý những thứ cron thật sự không diễn đạt được gọn: Mon..Fri *-*-* 09..17:00:00 (ngày thường, giờ làm việc), hoặc *:0/15 với RandomizedDelaySec=10m để ngăn một nghìn máy dập server cùng một khoảnh khắc.

Làm sao test systemd timer mà không phải chờ?

Ba lệnh trả lời mọi thứ. Liệt kê cái gì được định lịch và khi nào chạy kế tiếp, chạy job bằng tay đúng như timer sẽ làm, rồi đọc log của nó:

systemctl list-timers --all                 # mọi timer, lần chạy kế + lần trước
sudo systemctl start backup.service         # bắn job ngay, cùng unit với timer
journalctl -u backup.service -f             # xem output của nó theo thời gian thực

Chú ý sự tách biệt: systemctl start backup.timer kích hoạt lịch; service mới là job. Nếu list-timers thấy timer của bạn, systemctl status backup.service màu xanh, và journal hiện output của bạn, thì cả chuỗi đang chạy đúng.

Làm sao chạy cron job bằng tay?

Cron job chạy với môi trường bị lược sạch, vì vậy “chạy trong shell của tôi, hỏng trong cron” là một giống bug riêng. Để tái hiện cron trung thực, chạy lệnh qua sh với đúng môi trường cron sẽ dùng:

crontab -l                                  # xác nhận đúng dòng đó
env -i SHELL=/bin/sh PATH=/usr/bin:/bin sh -c '/usr/local/bin/backup.sh'
grep CRON /var/log/syslog | tail            # cron có bắn nó chưa? (Debian/Ubuntu)
journalctl -u cron -n 20                    # tương tự, trên distro systemd

Dòng env -i đó là bài test thủ công trung thực nhất: một môi trường trống với PATH default của cron. Đa số lỗi cron im lặng là do PATH trống hoặc một % không được quote trong lệnh (cron coi % là ký tự xuống dòng), và cả hai lộ ra ngay theo cách này.

Vì sao systemd timer của tôi không kích hoạt?

Bốn nguyên nhân phủ gần như mọi trường hợp, theo thứ tự cần kiểm tra:

  1. Tên service và timer không khớp. foo.timer bắn foo.service — một OnFailure gõ sai hoặc unit bị đổi tên nghĩa là timer “chạy” vào hư không. systemctl cat foo.timer cho thấy chính xác nó nhắm vào đâu.
  2. Timer đã bị sửa nhưng chưa reload. Sau khi đổi unit file: sudo systemctl daemon-reload && sudo systemctl restart foo.timer. Thiếu bước này lịch mới của bạn chưa có hiệu lực.
  3. Persistent=true mà không có ngữ nghĩa OnCalendar bạn mong đợi — hoặc bạn đang xem systemctl status foo.timer (luôn hiện active kể cả khi rảnh) thay vì list-timers.
  4. Service nó bắn fail ngay lập tức, nên timer trông như chết. journalctl -u foo.service --since -1h sẽ hiện cú crash mà list-timers che khuất.

Và khi bạn thật sự nhìn vào log, journalctl cheat sheet có đủ filter (-u, --since, -f) để làm việc này nhanh.

Cron vs systemd timer: bảng quyết định

cronsystemd timer
Thiết lậpmột dòng crontabhai unit file
Logthư local, thường không ai đọcjournal, theo từng unit
Lần chạy lỡ (máy tắt)bị bỏ quachạy một lần với Persistent=true
Dependency / thứ tựkhông — tự lo trong scriptđủ bộ dependency của unit
Delay ngẫu nhiêntự làm với $RANDOMRandomizedDelaySec=
Test/dry-run lịchkhôngsystemd-analyze calendar
Có mặt khắp nơicó — container, BSD, embeddedcần systemd (PID 1)
Job user không cần rootcrontab -eunit systemd --user

Kinh nghiệm rút gọn: đưa một job lên máy systemd của bạn → timer. Nhắc việc cá nhân nhanh hoặc một máy bạn không dựng → cron. Bất cứ thứ gì có dependency, retry, hay cần biết nó có chạy thật không → timer, luôn luôn. Một pattern phổ biến là timer chạy job bảo trì — ví dụ backup rsync mỗi đêm — nơi Persistent=true bảo đảm backup vẫn diễn ra dù máy ngủ vào đúng phút định lịch, thứ cron đơn giản không đưa được.

— mrsaynothing

— mrsaynothing

Ghi chú thực địa về AI, Linux và self-hosting.

Thảo luận bài này trên dev.to dev.to ↗

Nhận how-to tiếp theo qua email

Một email mỗi bài viết. Sửa xong rồi đi tiếp.

self-hosted · không bên thứ ba · hủy đăng ký một cú bấm

cái này là gì?

llama.cpp vs Ollama: Nên chạy cái nào năm 2026?

Thích kiểu viết này? Tôi build như vậy để kiếm sống. thuê tôi