8 điểm bởi GN⁺ 2026-06-02 | 2 bình luận | Chia sẻ qua WhatsApp
  • systemd timer là lựa chọn thay thế thực dụng cho cron, dùng để chạy các unit như .service theo lịch và giúp quản lý lịch sử, đầu ra, môi trường rõ ràng hơn
  • cron truyền thống có các điểm yếu như $PATH mơ hồ, stdout/stderr dễ bị thất lạc, lịch sử chạy khó theo dõi, và cú pháp lịch khó đọc
  • Timer liên kết .timer.service cùng stem, và dùng OnCalendar, OnBootSec, OnUnitActiveSec để biểu đạt việc chạy theo thời điểm hoặc theo sự kiện
  • Có thể dùng systemd-analyze calendarsystemctl list-timers để kiểm tra biểu thức thời gian và thời điểm chạy tiếp theo; WakeSystem= có thể đánh thức máy để chạy ngay cả khi đang ngủ
  • RandomizedOffsetSecFixedRandomDelay= giúp giảm đỉnh chạy đồng thời, còn Persistent= sẽ bù ngay sau khi máy trực tuyến trở lại cho các lần chạy bị lỡ khi timer không hoạt động

Vì sao dùng systemd timer để thay cron

  • cron job là cách gọi phổ biến để chỉ thành phần cơ bản trong điện toán dùng để chạy tác vụ theo lịch như “chạy việc này mỗi ngày”, “chạy việc kia mỗi tháng”, kể cả khi tác vụ đó không do daemon cron thực sự thực hiện
  • systemd timer là một unit của systemd dùng để chạy một unit khác, thường là .service, theo lịch cụ thể, và có thể trở thành lựa chọn thay thế về mặt chức năng cho daemon cron truyền thống
  • cron truyền thống có một số điểm yếu trong thực tế vận hành
    • Thiết lập $PATH mơ hồ khiến kết quả chạy script khó dự đoán
    • Đầu ra stdoutstderr thường rơi vào hố đen hoặc bị gửi vào hệ thống mail của máy chủ
    • Khó theo dõi và truy vấn lịch sử thực thi
    • Cú pháp lịch như 01,31 04,05 1-15 1,6 * không dễ đọc hay trực quan với con người
  • systemd timer giảm bớt các vấn đề này đồng thời vẫn cung cấp cấu hình lịch kiểu lịch tương tự cron

Cấu trúc cơ bản: service và timer

  • systemd timer cần một đối tượng để chạy, và unit .service về mặt logic có thể xem như một script
  • Ví dụ, nếu đặt unit sau tại /etc/systemd/system/roulette.service thì sẽ cài một service có xác suất 1 trên 10 tắt máy tính
[Unit]
Description=1 in 10 chance to break your chains

[Service]
ExecStart=/usr/bin/env bash -c '[[ $(($RANDOM % 10)) == 0 ]] && systemctl poweroff || echo LIVE ANOTHER DAY'
  • ExecCondition= là cách tích hợp hơn để biểu đạt việc chạy có điều kiện bằng tùy chọn service của systemd, đồng thời thể hiện rõ hơn ở cấp unit rằng “có nên tiếp tục chạy hay không?”
[Unit]
Description=1 in 10 chance to break your chains

[Service]
ExecCondition=/run/current-system/sw/bin/bash -c '[[ $(($RANDOM % 10)) == 0 ]]'
ExecStart=/run/current-system/sw/bin/systemctl poweroff
  • Nếu điều kiện không thỏa, journal sẽ ghi lại thông báo rõ ràng hơn
May 05 11:05:32 diesel systemd[3117]: Condition check resulted in 1 in 10 chance to break your chains being skipped.
  • Nhìn chung, tận dụng các tùy chọn systemd cung cấp thường mang lại trải nghiệm tốt hơn so với tự viết script
    • OnFailure= có thể dùng khi cần phản ứng với việc script service thất bại
    • Restart= có thể dùng để thử phục hồi khỏi lỗi tạm thời

Liên kết unit timer và thực thi

  • Đặt /etc/systemd/system/roulette.timer với cùng stem tên file sẽ giúp liên kết timer với roulette.service
[Unit]
Description=impending destruction

[Timer]
OnCalendar=10:00

[Install]
WantedBy=timers.target
  • Mặc định, thiết lập Unit= của timer sẽ chọn unit service cùng stem với hậu tố .service
    • Trong ví dụ này, roulette.service sẽ được chọn
    • Nếu muốn chạy một unit service tên khác, có thể đổi Unit=
  • Đối tượng trong ExecStart= mặc định không được chạy như lệnh shell
    • Đích có đường dẫn tuyệt đối cần được xử lý như script hoặc như trình thông dịch nhận script dưới dạng đối số chuỗi
    • ExecStart=/usr/bin/echo Hello | /usr/bin/awk sẽ không hoạt động trong ngữ cảnh này vì pipe không có ý nghĩa
  • Các đối số của ExecStart= mặc định không kế thừa biến môi trường ngoài một số giá trị mặc định của system manager
    • $PATH mặc định gần như trống
    • Chạy /usr/bin/env là một biện pháp bảo vệ đơn giản để các mục như systemctl vẫn dùng được
    • Nếu chỉ dùng ExecStart=/usr/bin/bash thì $PATH sẽ có các mục mặc định, nhưng dùng env là lớp an toàn bổ sung
  • Có thể chạy service trực tiếp mà không cần timer
systemctl start roulette
  • Service không có phần [Install] thì không thể enable; trong cấu trúc này, timer là cách chuẩn để chạy service một cách nhất quán
  • systemctl mặc định vẫn thao tác với roulette.service ngay cả khi không ghi hậu tố rõ ràng
  • Áp dụng systemctl start cho unit .timer sẽ đưa timer vào trạng thái hoạt động, nhưng không chạy ngay service đích trong Unit=
systemctl start roulette.timer
  • status sẽ hiển thị lần tiếp theo timer sẽ chạy
systemctl status roulette.timer
Trigger: Sat 2026-04-18 10:00:00 MDT; 35min left
  • Luồng đơn giản nhất là tạo service đích, đặt timer có lịch ở cùng vị trí, rồi khởi động timer thay vì khởi động target
  • Nếu [Install] của unit timer có WantedBy= thì cũng có thể để timer tự lên cùng lúc khởi động máy
systemctl enable roulette.timer

Biểu đạt thời gian: sự kiện lịch và khoảng thời gian

  • Trong timer, cách biểu đạt lịch là điều quan trọng, và cần phân biệt giữa khoảng thời gian lặp lại với sự kiện lịch hoặc timestamp
  • Trang manual systemd.time(7) có nhiều ví dụ hữu ích và đáng là tài liệu đầu tiên để tham khảo khi viết timer
  • systemd-analyze có thể kiểm tra và diễn giải biểu thức thời gian
systemd-analyze calendar '*-*-* *:*:*'
Normalized form: *-*-* *:*:*
    Next elapse: Sat 2026-04-18 16:44:26 MDT
       (in UTC): Sat 2026-04-18 22:44:26 UTC
       From now: 431ms left
  • systemd timer không chỉ hỗ trợ thời điểm lặp lại theo đồng hồ thực, mà khác với cron truyền thống, còn cho phép định nghĩa khoảng thời gian lặp lại dựa trên một sự kiện trước đó
  • Dạng đầy đủ của daily có nghĩa là chạy lúc 00:00:00 mỗi năm, mỗi tháng, mỗi ngày
*-*-* 00:00:00
│ │ │ │  │  ╰── at second 00
│ │ │ │  ╰───── at minute 00
│ │ │ ╰──────── at hour 00
│ │ ╰────────── every day
│ ╰──────────── every month
╰────────────── every year
  • Có thể dùng các dạng viết tắt như daily, dạng đầy đủ, và các giá trị khác được systemd.time(7) hỗ trợ; systemd-analyze giúp kiểm chứng các giả định đó

Khi chạy theo sự kiện phù hợp hơn

  • Trong công việc thực tế, nhiều khi cách diễn đạt “chạy sau một sự kiện khác” phù hợp hơn là “chạy mỗi ngày vào cùng một giờ”
  • Với tác vụ dọn thư mục tạm, nếu biểu thức cron ngay sau lúc khởi động đã trôi qua thì /tmp có thể hầu như chẳng có gì để dọn
  • Diễn đạt là “chạy sau một giờ kể từ khi máy khởi động, rồi sau đó chạy mỗi giờ” sẽ khớp hơn với hành vi thực của service và logic lịch
[Timer]
OnBootSec=1h
OnUnitActiveSec=1h
  • OnBootSec=1h nghĩa là chạy một lần sau 1 giờ kể từ lúc máy khởi động
  • OnUnitActiveSec=1h nghĩa là chạy lại sau 1 giờ kể từ khi Unit= đã được thực thi, khiến timer ngầm tiếp tục lặp mãi
  • Kiểu biểu đạt chu kỳ như vậy thường phù hợp hơn cho các tác vụ “thỉnh thoảng chạy một lần” so với kiểu “chạy vào phút này của mỗi giờ”
  • Trong ví dụ bot Slack polling API của Advent of Code, biểu thức cron */15 đúng với chính sách “mỗi 15 phút” của API, nhưng nếu ai cũng polling như nhau thì có thể gây dồn lưu lượng
  • Nếu khởi động timer sau khi sửa mã và để nó chạy mỗi 15 phút kể từ đó, vẫn đáp ứng yêu cầu mà còn có khả năng giảm vấn đề thundering herd

Xem trạng thái timer trong nháy mắt

  • systemctl list-timers là lệnh cấp cao giúp tóm tắt tình trạng timer trên một máy
systemctl list-timers
NEXT                                 LEFT LAST                                  PASSED UNIT                         ACTIVATES
Mon 2026-04-20 15:15:00 MDT      1min 40s Mon 2026-04-20 15:00:05 MDT        13min ago zfs-snapshot-frequent.timer  zfs-snapshot-frequent.service
Mon 2026-04-20 15:32:16 MDT         18min Mon 2026-04-20 14:22:15 MDT        51min ago fwupd-refresh.timer          fwupd-refresh.service
Mon 2026-04-20 16:00:00 MDT         46min Mon 2026-04-20 15:00:05 MDT        13min ago logrotate.timer              logrotate.service
Mon 2026-04-20 16:00:00 MDT         46min Mon 2026-04-20 15:00:05 MDT        13min ago zfs-snapshot-hourly.timer    zfs-snapshot-hourly.service
Tue 2026-04-21 00:00:00 MDT            8h Mon 2026-04-20 09:43:22 MDT     5h 29min ago zfs-snapshot-daily.timer     zfs-snapshot-daily.service
Tue 2026-04-21 07:31:28 MDT           16h Sun 2026-04-19 20:15:47 MDT           7h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Mon 2026-04-27 00:00:00 MDT        6 days Mon 2026-04-20 09:43:22 MDT     5h 29min ago zfs-snapshot-weekly.timer    zfs-snapshot-weekly.service
Mon 2026-04-27 01:09:27 MDT        6 days Mon 2026-04-20 09:43:22 MDT     5h 29min ago fstrim.timer                 fstrim.service
Mon 2026-04-27 04:28:38 MDT        6 days Mon 2026-04-20 09:43:22 MDT     5h 29min ago zpool-trim.timer             zpool-trim.service
Fri 2026-05-01 00:00:00 MDT 1 week 3 days Wed 2026-04-01 10:07:51 MDT 1 week 1 day ago zfs-snapshot-monthly.timer   zfs-snapshot-monthly.service
Fri 2026-05-01 03:17:17 MDT 1 week 3 days Wed 2026-04-01 10:07:51 MDT 1 week 1 day ago zfs-scrub.timer              zfs-scrub.service

11 timers listed.
Pass --all to see loaded but inactive timers, too.
  • Chỉ với một lệnh là có thể nhìn toàn cảnh các mục đang chạy theo lịch timer
  • list-timers là một phần của nhóm lệnh con systemd thường dùng
    • list-units cũng hữu ích
    • list-paths là lệnh con mới được thêm vào systemctl gần đây hơn

Đánh thức máy đang ngủ để chạy

  • WakeSystem= có thể cho phép timer khi đến hạn sẽ đánh thức hệ thống khỏi trạng thái ngủ
WakeSystem=
    Takes a boolean argument. If true, an elapsing timer will
    cause the system to resume from suspend, should it be
    suspended and if the system supports this.
...
  • Tính năng này hữu ích khi cần chạy một script quan trọng mà không cần hành động vật lý như người dùng mở nắp laptop
  • Trên các bản phân phối như Arch hay NixOS vốn hỗ trợ tải trước gói cập nhật trước khi dùng, có thể tải gói cập nhật vào đêm khuya rồi sáng hôm sau cập nhật khi đã ngồi trước bàn phím
  • Manual có nói rằng nếu muốn hệ thống ngủ lại sau khi .service kết thúc thì cần tự xử lý việc đưa máy về chế độ ngủ lần nữa

Phân tán thời điểm chạy và giảm thundering herd

  • Vấn đề thundering herd là vấn đề hệ thống xảy ra khi nhiều tiến trình cùng thức dậy một lúc
  • Nếu toàn bộ hệ thống Debian trên thế giới đều bị hardcode chạy apt update lúc 00:00:00, thì nửa đêm sẽ trở thành thời điểm đỉnh lưu lượng tệ hại cho tất cả
  • FixedRandomDelay=RandomizedOffsetSec= giúp phân tán thời điểm thực thi
FixedRandomDelay=
    Takes a boolean argument. When enabled, the randomized delay
    specified by RandomizedDelaySec= is chosen deterministically,
    and remains stable between all firings of the same timer,
    even if the manager is restarted. ...

RandomizedOffsetSec=
    Offsets the timer by a stable, randomly-selected, and evenly
    distributed amount of time between 0 and the specified time
    value. ...
  • Có thể dùng các thiết lập này trên hệ thống thực tế để kiểm tra cập nhật phần mềm
  • Việc phân bố thời điểm chạy theo phân phối đều giúp giảm vấn đề thundering herd, làm hành vi nhất quán hơn, và tránh các yếu tố gây nhiễu như daemon khởi động lại trong lúc đang điều phối dịch vụ phân tán
  • Nhìn chung, các tùy chọn về thời gian rất giàu khả năng cấu hình và cho phép kiểm soát chi tiết

Bù ngay các lần chạy bị lỡ

  • Persistent= đặc biệt phù hợp với các script theo lịch không nên bị bỏ qua do laptop đang ngủ, nhưng cũng chưa cần đến WakeSystem=
Persistent=
    Takes a boolean argument. If true, the time when the service
    unit was last triggered is stored on disk. When the timer is
    activated, the service unit is triggered immediately if it
    would have been triggered at least once during the time when
    the timer was inactive. ...
  • Nếu một hệ thống có lịch check-in quản lý cấu hình gặp downtime, chỉ cần bật Persistent= trong .timer là có thể hội tụ lại trạng thái đúng ngay sau khi máy trực tuyến trở lại
  • Nếu không có Persistent=, có thể phải chờ đến thời điểm chạy bình thường tiếp theo của timer, và khoảng chờ đó có thể rất dài
  • Những tác vụ khác cũng không nên chờ sau khi phát hiện lỡ kích hoạt gồm cập nhật hệ thống, kiểm tra batch job, v.v.

Những điểm cần chú ý khi viết timer

  • Timer trong ngữ cảnh user manager được quản lý bằng systemctl --user vẫn hoàn toàn hợp lệ, nhưng cần chú ý target được ghi trong [Install]
  • Tùy bản phân phối, target phù hợp cho user timer có thể là default.target
  • Cũng như cron, lưu ý chung về việc phải giữ đồng hồ hệ thống chính xác vẫn hoàn toàn áp dụng
  • Người dùng systemd có thể kiểm tra trạng thái đồng bộ bằng timedatectl timesync-status
  • Nhiều trình soạn thảo hỗ trợ sẵn định dạng file unit của systemd, rất hữu ích khi file unit bắt đầu dài ra
  • Trên Emacs có thể dùng gói emacs systemd

2 bình luận

 
GN⁺ 2026-06-02
Ý kiến trên Hacker News
  • Tôi chưa dùng systemd timer đủ nhiều để phản biện mạnh, nhưng không rõ lắm nhận định rằng $PATH của cron mơ hồ
    Bạn có thể đặt PATH ngay trong crontab, nên tôi không thấy lý do gì để cho rằng nó khó đoán hơn các giá trị được thiết lập ở những nơi như /etc/bashrc, ~/.bashrc, ~/.profile, ~/.bash_profile, /etc/systemd/…
    Tôi dùng Linux từ năm 1994 nhưng không thuộc lòng cú pháp cron. Dù vậy, trong chú thích của crontab đã có sẵn m h dom mon dow command, nên chỉ cần điền số vào đúng tiêu đề là được
    Những phàn nàn còn lại thì tôi hiểu, và lần tới nếu cần một tác vụ cron, tôi định sẽ thử systemd timer

    • Câu “chỉ cần điền số vào đúng tiêu đề” không phải là cách tóm tắt công bằng cho chỉ trích ban đầu, vì đó không phải toàn bộ cú pháp
      Còn có dấu phẩy, dấu gạch chéo, dấu sao và các tổ hợp của chúng; nếu cần ngẫu nhiên hóa thì thường cron tự thân không làm được nên phải nhét vào trong lệnh. Việc viết một đặc tả cron không tầm thường là không hề dễ
    • Với tư cách người từng làm việc với các ứng dụng hỗ trợ biểu thức cron, các con số chỉ là phần cơ bản nhất của ngôn ngữ đó
      Khi ai đó nhập thứ như 5,3/4 4-8,11 1 4,5,6,9-11 */2, bạn sẽ có niềm vui phải reverse-engineer xem họ thực sự định làm gì, mà thường thì nó không mang nghĩa như họ đã viết
      Nếu thêm cả các phần mở rộng chỉ được hỗ trợ trong một số môi trường cron thì còn phức tạp hơn nữa
      systemd timer dễ quản lý hơn nhiều. Khả năng kiểm soát việc có cho phép chạy chồng lặp hay không với các tác vụ chạy lâu, hoặc chạy tác vụ trong một khoảng từ lúc bắt đầu đến lúc kết thúc thay vì tại một thời điểm cố định, là những cải tiến lớn
      Trước đây tôi từng có một tác vụ sao lưu mắc vào vòng lặp symbolic link khiến VPS sập, và cron vẫn tiếp tục khởi tạo các tác vụ sao lưu mới dù bản sao lưu trước còn chưa xong
      Việc phải viết lại lệnh và script do PATH đặc thù của CRON cũng rất bất tiện, dù ở một số systemd timer cũng có thể tương tự. Dù vậy, ít nhất bạn có thể chạy timer thủ công mà không cần sửa crontab để nó chạy sau 30 giây rồi ngồi chờ
    • Tôi không muốn hard-code $PATH trong crontab chỉ để test tác vụ cron
      Nếu không hard-code thì $PATH khi cron thực thi sẽ khác với $PATH lúc bạn tự chạy thử lệnh. systemctl start foo.service khởi chạy lệnh trong cùng môi trường với khi timer kích hoạt, nên bạn biết nó sẽ hoạt động theo cùng cách hay không
      Ngược lại, tác vụ cron sẽ chạy vào thời điểm ghi trong crontab. systemd timer thì phần lớn sẽ kích hoạt vào thời điểm chỉ định, nhưng do lỗi logic của systemd, có thể nó chạy một lần vào ngày 29 tháng 2 rồi không bao giờ chạy lại nữa, hoặc khi bạn “restart” timer unit thì có thể kích hoạt hoặc không
    • Điểm hay của môi trường systemd là nó tiêu chuẩn và gần như trống rỗng. Trong khi đó môi trường crontab hoàn toàn khác với môi trường mà các script supervisord hay sysvinit kế thừa, nên tôi từng bị dính khá nhiều
      Trong systemd, bất kể thứ gì kích hoạt thì unit thực sự được chạy vẫn là cùng một unit, nên không có khoảng cách đó
      Bạn vẫn cần biết môi trường mặc định là gì, nhưng đó là một môi trường gần như sạch và không bị shell tác động. Tôi xem đây là ưu điểm của systemd
    • Tôi sẽ không nói đến mức PATH là mơ hồ, nhưng cron đúng là có vấn đề liên quan đến PATH
      Giá trị mặc định thiếu những thứ mà người ta dễ mong đợi như /usr/local/bin hay /usr/sbin cho root, và một số bản phân phối như Arch Linux thậm chí không ghi đường dẫn mặc định hay khuyến nghị cấu hình trong trang hướng dẫn
      Nếu chỉ muốn thêm đường dẫn cho một script cụ thể thì bạn phải bọc bằng env, hoặc cấu hình trong wrapper script, hoặc đổi đường dẫn trước mục đó rồi đổi lại sau
      Bạn không thể dùng ~ hay $HOME trong PATH mà phải viết toàn bộ đường dẫn tuyệt đối, nên với crontab của người dùng thì đặc biệt phiền
      Không phải là khó lách qua, nhưng mặc định dùng cùng đường dẫn với các dịch vụ khác thì systemd timer vẫn mang lại trải nghiệm tốt hơn
  • Tôi chuyển từ cronie sang systemd timer vì nó linh hoạt hơn với thời điểm hệ thống khởi động
    Chiến lược sao lưu của tôi là tạo các mục lưu trữ borg vào một giờ cố định mỗi ngày, nhưng cronie đòi hỏi hệ thống phải đang bật đúng lúc đó. systemd timer chịu được tình huống này và sẽ chạy dịch vụ ngay khi hệ thống sẵn sàng dùng
    Kho lưu trữ tự động hóa sao lưu là https://github.com/gchamon/borg-automated-backups

    • Cronie có một cơ chế cho việc này tên là anacron. Trên hệ thống của tôi, cron gọi /etc/cron.hourly/0anacron mỗi giờ, và dù có lỡ thời điểm chạy sớm nhất thì nó vẫn thực hiện các tác vụ trong /etc/cron.{daily,weekly,monthly}. Bạn cũng có thể đặt độ trễ ngẫu nhiên
      Nếu chỉnh /etc/anacrontab thì có thể tạo lịch tùy chỉnh
      Ở cấp người dùng, có lẽ bạn có thể thêm một mục như @hourly anacron -t /path/to/anacrontab -S /path/to/spooldir vào crontab của người dùng, dù tôi chưa tự thử
      Nhiều triển khai cron cũng có cơ chế tương tự
    • cron có tùy chọn @reboot, tôi dùng nó cho vài script và nó hoạt động tốt
    • Cronie không có meta trigger @reboot sao?
  • Không tin lắm vào đầu phun máy in Canon vì nếu để không một thời gian thì nó có thể bị tắc. Thế là tôi bảo Claude viết script systemd để mỗi tuần in ra ảnh chó con, đồng thời đảm bảo có đủ phổ CMYK để máy in phải hoạt động thật sự
    Mỗi sáng thứ Hai ngồi vào bàn mà thấy máy in đột nhiên nhả ra một tấm ảnh thì cũng là một kiểu bất ngờ khá vui

    • Sẽ hay hơn nếu máy in có chế độ in ảnh ngẫu nhiên từ album hoặc lịch, thay vì vài ngày lại xả mực phí phạm vào miếng bọt biển
      Ít ra cũng có thể thành ý tưởng cho dự án hội thi khoa học của bọn trẻ
    • Bố tôi từng có một mẫu gần giống Deskjet 720
      Sau khi ông mất, nó bị bỏ không vài năm và còn bị ngắt điện hẳn, nhưng lúc cần in màu thì tôi chỉ cắm điện rồi in luôn
      Đến khoảng 1/5 trang đầu tiên thì mọi màu đều trở lại, và sau đó nó in thêm khoảng 20 trang nữa mà không vấn đề gì
    • Hồi mới vào đại học tôi cũng từng làm điều tương tự với một chiếc Samsung ML-2010 cũ
      Có vẻ giống vấn đề phần mềm hơn là phần cứng: nếu để máy in nối với máy tính mà không dùng hơn một tuần thì nó cứ thế ngừng in
      Tôi có thể đã đào log để tìm nguyên nhân, nhưng thay vào đó lại tạo một cron job in trang kiểm tra vào thứ Hai và thứ Năm. Ở đầu trang kiểm tra chỉ có dòng như LOL PRINTER WORKS
      Thực ra cũng không lãng phí như tưởng tượng. Tôi học khá nhiều môn toán nên cần rất nhiều giấy in một mặt để giải bài; tôi dùng các bản in lỗi hoặc bản in thử trước, rồi mới dùng giấy trắng
    • Máy in laser mới là đáp án. Chỉ riêng khoản tiết kiệm vật tư tiêu hao cũng đủ hoàn vốn
    • Tôi định giới thiệu máy in màu LED OKI giá rẻ, nhưng họ đã rút khỏi thị trường tiêu dùng rồi
      Độ phân giải tối đa chỉ 600dpi nhưng màu rất đẹp và đồng đều, và việc toner không bị khô là tiêu chí mua hàng cốt lõi của anh tôi. HP inkjet của anh ấy đã bị tắc nhiều lần
  • Tôi cực kỳ thích systemd timer. Tôi đã dần chuyển toàn bộ các cron job từng triển khai bằng Ansible sang timer, và giờ chỉ cần Ansible copy là xong
    Tích hợp với journalctl đặc biệt tốt, và còn tốt hơn trên các OS mới nơi syslog biến mất, như Debian 13. Việc có thể khởi chạy service thủ công để debug cũng rất tiện
    Cron job bị lỗi trước đây thường là kiểu phiền phức phải copy-paste hoặc viết thêm shell script, chưa kể hố đen nuốt mất standard output của cron job
    Cũng có thể giám sát như các service systemd bình thường và nhận cảnh báo khi thất bại. Tôi cũng đánh giá cao việc các dự án mã nguồn mở ngày càng khuyến nghị timer như một cách triển khai

    • Tôi thấy việc dự án khuyến nghị timer là ổn, nhưng phải cho phép bỏ qua để dùng cron thì tôi mới thấy hài lòng
  • NixOS mặc định dùng systemd nên coi nó như thành phần hạng nhất trong quản trị. Điều này đặc biệt hay nếu trước đó bạn từng dùng launchd trên macOS
    Tôi cũng thích việc khi phân phối công cụ cho NixOS, có thể tận dụng systemd một cách tự nhiên chứ không phải gắn thêm như miếng vá tạm
    Tuy vậy, nếu phải phân phối công cụ có nhiều quản lý vòng đời cho toàn bộ người dùng Linux, tôi vẫn băn khoăn nên làm sao vì systemd không phải ở đâu cũng có
    Tôi đang chạy scrub hàng tháng cho pool btrfs bằng systemd timer. Nó khá hữu ích vì có thể quyết định liệu khi người dùng tự chạy scrub thì có bỏ qua lịch tiếp theo không, hoặc nếu là tác vụ hàng tháng mà thiết bị đã tắt 6 tháng thì sẽ dồn backlog hay gộp lại thành một lần chạy

    • Trên NixOS, job systemd thực sự rất dễ. Định nghĩa unit bằng Nix còn tốt hơn là vật lộn với file INI
      systemd.services.sync-recyclarr = { serviceConfig.Type = "oneshot"; path = [ pkgs.podman ]; script = '' podman exec -it recyclarr recyclarr sync radarr podman exec -it recyclarr recyclarr sync sonarr ''; };
      systemd.timers.sync-recyclarr = { timerConfig = { OnCalendar = "daily"; Persistent = true; Unit = "sync-recyclarr.service"; }; partOf = [ "sync-recyclarr.service" ]; requires = [ "podman-recyclarr.service" ]; wantedBy = [ "timers.target" ]; };
    • Không biết bạn có đang định nghĩa trực tiếp trong file flake.nix không
      Tôi cũng dùng NixOS, nhưng giữ toàn bộ cấu hình ở định dạng gốc rồi chỉ dùng Nix để tạo symbolic link. Làm vậy thì cũng dễ mang cấu hình sang các hệ thống non-NixOS hơn
      Vấn đề là NixOS có vẻ không nhận và chạy các systemd timer cùng service đặt trong thư mục ~/.config/systems/user, và những thứ như WantedBy=default.target dường như cũng không có tác dụng
      Vì thế sau khi phải tự khởi động lại mọi service bằng tay sau mỗi lần reboot, tôi mới thấy mình đồng ý rằng systemd timer đúng là tuyệt vời
  • Timer không nhất thiết chỉ chạy với service unit cùng tên mà còn có thể làm việc với các unit tùy ý, nên linh hoạt hơn mong đợi
    Trên server của tôi có một timer khởi chạy backup.target, thứ sẽ chạy toàn bộ chu trình sao lưu gồm restic backup, restic prune, restic forget, kèm thời điểm bắt đầu ngẫu nhiên mỗi sáng và thông báo
    Các unit restic-* thực tế là Podman Quadlet, nên miễn là server có Podman và Systemd thì cấu hình đó vẫn chạy được bất kể nội dung cụ thể trên server là gì
    Tuy vậy, timer là một trong những kiểu unit systemd thô ráp nhất để dùng hằng ngày. Tôi hiểu vì sao nó tách làm hai file và cú pháp start với enable lại khác nhau, nhưng đôi khi tôi chỉ muốn tạo một file, chạy script rồi xong

    • Tôi cũng dùng cấu hình tương tự cho backup. Có lần tôi tắt timer để làm việc khác với kho restic, như dọn lock chẳng hạn, rồi bị dính vì không nhận ra unit đã được trigger từ trước vẫn đang chạy
    • Có vẻ cần thêm một lớp trừu tượng phía trên systemd unit. Thay vì chỉnh file trực tiếp thì sẽ tốt hơn nếu có một công cụ dòng lệnh mang tính khai báo xử lý chuyện đó
      Trong thời đại LLM thì có thể đây không còn là vấn đề lớn, nhưng nó vẫn cho cảm giác hơi phiền một chút mỗi lần làm
    • Tôi thắc mắc vì sao lại ngẫu nhiên hóa thời gian backup
  • Dù không phải lúc nào tôi cũng cực kỳ thích mọi khía cạnh của systemd, nhưng nhìn chung tôi đồng ý với cảm nhận này
    Với các tác vụ theo lịch ở cấp độ “hệ thống”, tôi gần như đã bỏ hẳn cron và chuyển sang ưu tiên systemd timer. Với việc lập lịch trong phạm vi một ứng dụng cụ thể, tôi có thể dùng thứ như Quartz
    Lý do thì khá mơ hồ và khó giải thích, nhưng cách làm của systemd khớp gọn gàng hơn với mô hình trong đầu tôi về kiểu “mọi thứ nên hoạt động như thế này”. Trước đây tôi cũng từng gặp khá nhiều trường hợp việc chạy script bằng cron có PATH mơ hồ nên khó đoán trước, dù đó không phải là tất cả
    Tôi không định khẳng định systemd timer phổ quát hay khách quan mà nói là tốt hơn cron, nhưng ít nhất nó đã thuyết phục được tôi

  • Đây là phần nhập môn về systemd timer rất hay, đủ thuyết phục để cuối cùng tôi cũng muốn thử dùng
    Tôi cũng thích list-timers. Với cron, không dễ để nắm được toàn bộ các tác vụ cron đang chạy trên một máy chỉ trong một cái nhìn. Phải kiểm tra crontab của mọi người dùng, /etc/cron.d/, cùng các thư mục daily/hourly/monthly
    Thực tế tôi có một trường hợp cần chạy một lần vào khoảng 5 phút sau khi khởi động, rồi sau đó khoảng mỗi 12 giờ lại chạy tiếp, nên thật tốt khi biết systemd timer xử lý được việc này

    • Cảm ơn lời khen. Trong bối cảnh systemd hiện được dùng rộng rãi như bây giờ, tôi thấy việc học cách dùng công cụ như systemd-analyzesystemctl list-timers thực sự rất đáng giá
  • systemd lúc mới nhìn thì phức tạp, nhưng dùng rồi thì không còn muốn dùng thứ khác nữa. Quản lý mọi thứ bằng systemctl rất tiện

    • Vẫn có những lựa chọn thiết kế kỳ lạ mà tôi chưa hoàn toàn hiểu nổi
      Ví dụ, tôi không hiểu vì sao định nghĩa unit nhất thiết phải là các tệp thật trên đĩa. Khi nạp lại daemon, nó đọc lại toàn bộ tệp chứ không chỉ những tệp đã thay đổi. Tôi vẫn nghĩ lẽ ra nên có một API để thêm unit theo cách lập trình được. Có vài thứ tương tự, nhưng bị ràng buộc nhiều và không linh hoạt
      Việc không thể khai báo nhiều unit trong một tệp cũng khá khó hiểu. Thiết kế xoay quanh hệ thống tệp và lựa chọn không đưa ra mức trừu tượng khác trông không hẳn là thông minh. Nó cũng chẳng đặc biệt tuân theo triết lý Unix
      Định dạng định nghĩa unit cũng vậy, nếu hồi đó đã có TOML thì có lẽ họ đã dùng thứ gì hợp lý hơn
    • systemd thật ra có trang manual khá hữu ích
    • Cũng có người nhìn theo hướng ngược lại. Dùng xong thì lại không muốn dùng nữa. Tôi thực sự ghét systemd
      Chắc là vì tôi già rồi. Hiển nhiên chỉ có systemd-* mới là con đường đúng duy nhất, còn ai nghĩ khác thì đều là mấy ông thích chỉ dạy đời mà thôi
    • Tôi vẫn ghét ghi log bằng journald
    • Đây là một góc nhìn khá hiện đại. Khi systemd mới xuất hiện, mọi người thực sự rất ghét nó, nhưng tôi thì luôn thích và nghĩ rằng cuối cùng rồi người ta cũng sẽ chấp nhận. Giờ thấy đúng là mọi chuyện đã thành ra như vậy nên tôi vui
  • Tôi đã dùng Linux hơn 20 năm, và systemd hơn 10 năm
    Thế mà lúc nào cũng vẫn có cái mới để học, và giờ tôi thực sự xem đây như thêm một công cụ hữu ích nữa

    • Tôi dùng Linux chắc cũng khoảng 30 năm rồi, apparently hóa ra chúng ta đã sai hết khi dùng cron suốt mấy chục năm qua
 
GN⁺ 2026-06-02
Ý kiến trên Lobste.rs
  • systemd không hoàn hảo, nhưng tôi có cảm giác nhiều quyết định thiết kế của nó dựa trên những bài học rút ra từ cách làm truyền thống trước đây
    Gần đây tôi nghe lại tập năm 2015 của CRE, nơi Lennart Poettering giải thích bối cảnh đó, và đến giờ vẫn đáng để giới thiệu

  • Tôi thuộc phe không thích systemd từ tận xương tủy, nhưng systemd.timers là một trong số ít khái niệm “còn đỡ hơn” của sản phẩm này
    Vì vậy tôi khá bất ngờ khi tác giả lại bảo vệ nó theo kiểu hạ thấp những người có phàn nàn chính đáng
    Dù vậy, dùng cùng lệnh at thì khá ổn. Với lệnh chỉ cần chạy một lần vào thời điểm cụ thể thì dùng at, còn lại thì dùng systemd timer và file unit đơn giản
    Điều tôi muốn thấy được cải thiện nhất là có thể biết người dùng nào đang chạy timer. Tôi có lẽ là một trong số ít người vẫn vận hành shellbox vào năm 2026, nhưng sẽ rất hữu ích nếu biết timer nào đang gõ đĩa mỗi giây là do người dùng nào tạo ra

    • Với mục đích này, có lẽ có thể dùng user unit thay vì bắt mọi người cài system timer
      Theo tôi biết thì với loginctl enable-linger, nó có thể chạy ngay cả khi không có phiên người dùng đang hoạt động. Tất nhiên sẽ có những trường hợp cách đó vẫn chưa đủ, và tôi không biết tình huống cụ thể
  • Tôi đặc biệt mong systemd timer có gánh nặng ban đầu thấp hơn ở phía quản lý người dùng
    Xét về lượng cấu hình cần thiết thì thực sự rất khó thắng được crontab -e

    • Cách làm của systemd, nơi để cấu hình một timer phải cần nhiều file cấu hình và service, thì… xét như một lựa chọn API là khó chấp nhận nổi
  • Tôi đã suy nghĩ khá lâu về cách thu thập log cron script một cách có hệ thống, rồi nhận ra là chỉ cần dùng systemd timer
    Thế là vấn đề logging được giải quyết. Giờ tôi không còn lý do gì để quay lại cron nữa, giá mà biết điều này sớm hơn

    • Chẳng phải chỉ cần pipe sang logger, hoặc nối vào file log bằng >>, hoặc cứ để mặc định rồi nhận email là được sao?
  • Cứ bảo là lỗi thời cũng được, nhưng tôi vẫn cấu hình email từ server gửi đến mình
    Nếu tự động hóa sẵn thì mỗi host mới đều có kèm theo miễn phí, và bình thường cũng khá tiện
    Ví dụ như mở một multiplexer, chạy long_running_process | mail root@localhost -s "done $?" rồi quên luôn

  • Bài viết hay, và tôi cũng từng có bản nháp một bài tương tự, đến gần đây lại phải tham khảo lại
    Nếu bạn giống tôi và đã chui vào hang thỏ systemd, thì tôi khuyên nên liên kết tượng trưng các file unit và timer trong thư mục project liên quan vào /etc/systemd/system/
    Một điều tôi không thích ở systemd là nó không phân biệt unit do distro cài với unit do mình tự viết, và dùng symbolic link thì có thể tự duy trì sự tách biệt đó

    • Thực ra sự phân biệt đó nằm ở đường dẫn
      Unit hệ thống/gói/phân phối nằm trong /usr/lib/systemd/system, còn local override hoặc local unit thì nằm trong /etc/systemd/system