Một timer ghi 03:00 nhưng server dùng UTC còn nhóm làm việc theo giờ Việt Nam. Một timer khác chạy ngay khi vừa được bật dù người vận hành nghĩ lịch phải chờ đến ngày mai. Cả hai tình huống cần đọc cấu hình thời gian và chính sách kích hoạt, không chỉ nhìn tên unit.
Bài này dùng service chỉ in timestamp để học cách kiểm tra lịch. Cú pháp calendar đã được thử trên systemd 255; tài liệu chính thức được đọc ngày 26/10/2026. Hai unit mẫu chưa được cài hoặc chạy trong lượt biên tập. Không có thay đổi timer đang vận hành trên server khi kiểm chứng bài này.
1. Đặt múi giờ ngay trong biểu thức
systemd.time mô tả biểu thức calendar và tên múi giờ IANA. Thay vì suy đoán timezone của máy, ví dụ dùng Asia/Ho_Chi_Minh trong lịch. Trước khi cài unit, kiểm tra nó bằng lệnh chỉ đọc:
systemd --version
systemd-analyze calendar --base-time='2026-10-25 00:00:00 UTC' --iterations=2 '*-*-* 03:00:00 Asia/Ho_Chi_Minh'
Với base time cố định trên môi trường đã thử, hai mốc UTC là 25/10/2026 lúc 20:00 và 26/10/2026 lúc 20:00. Chúng tương ứng 03:00 Việt Nam của ngày tiếp theo. Đối số base-time giúp kiểm tra có thể lặp lại mà không phụ thuộc bạn đọc bài vào ngày nào.
Đừng lấy dòng “From now” trong output cũ làm lịch tương lai. Hãy đọc normalized form, múi giờ và các mốc cụ thể từ lần chạy trên máy của bạn.
2. Tạo một service thử có tác dụng rõ ràng
Trên máy Linux thử nghiệm có systemd và GNU date, lưu /etc/systemd/system/demo-vn-clock.service:
[Unit]
Description=Print timestamp for calendar timer demonstration
[Service]
Type=oneshot
ExecStart=/usr/bin/date --iso-8601=seconds
Service chỉ in thời gian rồi kết thúc. Nó chưa phải tác vụ đồng bộ hoặc backup. Khi thay bằng công việc thật, cần thiết kế quyền chạy, thời gian chờ, kết quả lỗi và khả năng chạy lại theo yêu cầu của công việc đó.
Lưu /etc/systemd/system/demo-vn-clock.timer:
[Unit]
Description=Run calendar timestamp demonstration at 03:00 Vietnam time
[Timer]
OnCalendar=*-*-* 03:00:00 Asia/Ho_Chi_Minh
Persistent=true
AccuracySec=1s
[Install]
WantedBy=timers.target
Theo systemd.timer, timer mặc định kích hoạt service cùng tên, khác phần đuôi. Vì vậy, hai tên demo-vn-clock ở đây cần khớp nhau. AccuracySec điều chỉnh cửa sổ chính xác của timer; đặt một giây không biến hệ điều hành thành một hệ thống bảo đảm thời gian thực tuyệt đối.
3. Hiểu điều Persistent thực sự cung cấp
Persistent lưu dấu thời gian kích hoạt trên đĩa cho timer OnCalendar. Khi timer được kích hoạt lại, nếu đã có ít nhất một lần lẽ ra phải chạy trong lúc nó không hoạt động, service có thể được kích hoạt để bù. Đây là lý do bật timer sau mốc lịch có thể tạo một lần chạy sớm hơn ngày kế tiếp.
Một trigger bù không tự tạo danh sách công việc cho từng ngày bị bỏ lỡ. Nếu ứng dụng cần xử lý riêng từng ngày, chính ứng dụng phải xác định ngày nào còn thiếu và chính sách được phép bù. Nếu không được phép bù dữ liệu cũ, cũng cần guard ở tầng nghiệp vụ thay vì chỉ dựa vào lịch.
Với ví dụ in timestamp, một lần chạy bù chỉ in thời điểm hiện tại. Đừng đọc output đó thành bằng chứng service đã thực hiện lại mọi công việc lịch sử. Timer là cơ chế kích hoạt, còn ý nghĩa của một lượt chạy thuộc về chương trình được gọi.
4. Kiểm tra unit rồi mới bật trên máy thử
Sau khi lưu đúng hai file, người có quyền quản trị máy thử có thể chạy:
sudo systemd-analyze verify /etc/systemd/system/demo-vn-clock.service /etc/systemd/system/demo-vn-clock.timer
sudo systemctl daemon-reload
sudo systemctl enable --now demo-vn-clock.timer
systemctl list-timers demo-vn-clock.timer --no-pager
journalctl -u demo-vn-clock.service --since today --no-pager
Các lệnh này là hướng dẫn thực hành, chưa được chạy cho unit mẫu trong lượt biên tập. Kiểm tra báo lỗi của verify, thời điểm NEXT của timer và log service. Bật timer không đồng nghĩa service đã hoàn thành công việc thành công; cần đọc trạng thái và log của đúng service.
Khi xong bài thử, tắt đúng timer demo:
sudo systemctl disable --now demo-vn-clock.timer
Lỗi thường gặp
Nếu NEXT lệch giờ, xem biểu thức có ghi timezone không và hệ thống có dữ liệu timezone phù hợp không. Nếu timer chạy nhưng service không hoàn tất, kiểm tra đường dẫn ExecStart và exit status. Nếu service vẫn active, lần timer tiếp theo không tự tạo thêm một instance; tài liệu timer lưu ý trường hợp này, đặc biệt với service giữ trạng thái active sau khi lệnh kết thúc.
Đừng thêm RemainAfterExit chỉ để trạng thái trông “đang chạy” cho một oneshot định kỳ. Cũng đừng kết luận timer chết chỉ vì list-timers chưa cho bạn bằng chứng nghiệp vụ; cần phân biệt lịch kế tiếp, lần kích hoạt và kết quả công việc.
Kết luận
Ghi múi giờ trong lịch, dùng calendar parser để kiểm tra và quyết định rõ cách xử lý lượt bị lỡ. Một service chỉ in thời gian là bước thử nhỏ trước khi đưa công việc thật vào timer và quan sát toàn bộ vòng vận hành.

