Định cấu hình dịch vụ lỗi hệ thống để chấm dứt thông qua SIGKILL


20

Lý lịch

Tôi đã được yêu cầu tạo một systemdkịch bản cho một dịch vụ mới, foo_daemonđôi khi rơi vào "trạng thái xấu" và sẽ không chết SIGTERM(có thể do trình xử lý tín hiệu tùy chỉnh). Đây là vấn đề đối với các nhà phát triển, vì họ được hướng dẫn bắt đầu / dừng / khởi động lại dịch vụ thông qua:

  • systemctl start foo_daemon.service
  • systemctl stop foo_daemon.service
  • systemctl restart foo_daemon.service

Vấn đề

Đôi khi, do foo_daemonrơi vào trạng thái xấu, chúng tôi buộc phải giết nó thông qua:

  • systemctl kill -s KILL foo_daemon.service

Câu hỏi

Làm cách nào tôi có thể thiết lập systemdtập lệnh của mình foo_daemonđể bất cứ khi nào người dùng cố gắng dừng / khởi động lại dịch vụ, systemdsẽ:

  • Cố gắng tắt máy duyên dáng foo_daemonthông qua SIGTERM.
  • Dành tối đa 2 giây để tắt / kết thúc foo_daemonhoàn thành.
  • Cố gắng ngừng hoạt động foo_daemonthông qua SIGKILLnếu quá trình vẫn còn tồn tại (vì vậy chúng tôi không có nguy cơ PID bị tái chế và systemdcác vấn đề SIGKILLchống lại PID sai). Thiết bị chúng tôi đang thử nghiệm sinh sản / tạo ra nhiều quy trình một cách nhanh chóng, do đó , có một mối lo ngại hiếm gặp nhưng rất thực về việc tái chế PID gây ra sự cố.
  • Nếu, trong thực tế, tôi chỉ hoang tưởng về việc tái chế PID, tôi đồng ý với kịch bản chỉ ban hành SIGKILLtheo quy trình 'PID mà không quan tâm đến việc tiêu diệt một PID tái chế.


2
Ngay cả khi bạn sinh ra các quá trình đủ nhanh để cuộn hơn 4 triệu PID trong hai giây, systemd không ngồi trong một vòng kiểm tra "cái pid này có còn sống không? Cái này có còn sống không?" bởi vì nó không cần phải làm vậy; nó đã được thông báo về việc liệu các tiến trình con ngay lập tức của nó có còn sống hay không (bằng SIGCHLD thông thường và Waitpid ()). Vì vậy, nếu thấy rằng quá trình đã thoát sau SIGTERM, thì đơn giản là nó sẽ đánh dấu dịch vụ là 'không hoạt động' tại thời điểm đó - nó sẽ không bận tâm đến việc kiểm tra, chờ đợi và gửi SIGKILL.
grawity

Câu trả lời:


26

systemd đã hỗ trợ điều này ngay lập tức và nó được bật theo mặc định .

Điều duy nhất bạn có thể muốn tùy chỉnh là thời gian chờ, điều bạn có thể làm với TimeoutStopSec=. Ví dụ:

[Service]
TimeoutStopSec=2

Bây giờ, systemd sẽ gửi SIGTERM, đợi hai giây để dịch vụ thoát ra và nếu không, nó sẽ gửi SIGKILL.

Nếu dịch vụ của bạn không nhận biết hệ thống, bạn có thể cần cung cấp đường dẫn đến tệp PID của nó PIDFile=.

Cuối cùng, bạn đã đề cập rằng daemon của bạn sinh ra nhiều quá trình. Trong trường hợp này, bạn có thể muốn đặt KillMode=control-groupvà systemd sẽ gửi tín hiệu đến tất cả các quy trình trong nhóm.


Cảm ơn bạn. Một câu hỏi cuối cùng: giả sử dịch vụ không nhận biết hệ thống. Tôi có thể thêm gì vào tập lệnh systemd cho dịch vụ này để systemd tạo / quản lý tập tin PID? Ngoài ra, dịch vụ có thể là đa thể qua các đơn vị mẫu, vì vậy chúng tôi thường khởi chạy nó thông qua `systemctl start foo_dameon@1.service", do đó, điều đó có ảnh hưởng đến logic tệp PID trong tập lệnh không?
Cloud

4
@DevNull systemd không tạo hoặc quản lý các tệp PID. Không có lý do cho nó để làm như vậy. Nếu dịch vụ của bạn không tạo tệp PID riêng, thì nếu có thể, hãy định cấu hình để chạy ở nền trước (thay vì daemonizing) và đặt Type=simpletrong đơn vị systemd.
Michael Hampton

1
Nếu dịch vụ có người phụ thuộc, Type=forkingcó lợi thế (nếu dịch vụ được viết đúng) thông báo cho systemd khi nó hoàn toàn 'sẵn sàng' mà Type = đơn giản không thể làm được. Daemonizing không phải là một vấn đề, ngay cả khi không có tệp PID - systemd sẽ theo dõi quá trình chính.
tham lam

1
@grawity Đúng như vậy ... mặc dù đó là kinh nghiệm của tôi khi các dịch vụ được kích hoạt trước khi chúng thực sự sẵn sàng để bắt đầu phục vụ. Một dịch vụ nhận biết hệ thống sử dụng Type=notifylà tốt nhất cho systemd và nhiều dịch vụ phổ biến đã làm điều này. Nhưng có lẽ không phải là dịch vụ di sản này. Trong trường hợp của OP, anh ta có một dịch vụ sinh ra nhiều quy trình. Các tài liệu systemd cảnh báo về trường hợp này .
Michael Hampton

1

Vì không ai đề cập đến nhu cầu Type=oneshot, đây là một ví dụ hoàn chỉnh xuất hiện do lỗi hết thời gian.

[Unit]
Description=timeout test

[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.