在 systemd 中使用 OnFailure 的正確方法
我有一個執行軟體的服務,如果它們不存在,它會生成一些配置文件,如果它們存在則讀取它們。我一直面臨的問題是這些文件有時會損壞,使軟體無法啟動,從而導致服務失敗。在這種情況下,我想刪除這些文件並重新啟動服務。
我嘗試通過執行以下操作創建一個在失敗時應該執行的服務:
[Service] ExecStart=/bin/run_program OnFailure=software-fail.service
該服務在哪裡:
[Service] ExecStart=/bin/rm /file/to/delete ExecStop=systemctl --user start software.service
然而,問題是該服務沒有啟動,即使該服務失敗了。
我試著做
systemctl --user enable software-fail.service
但是每次系統啟動時它都會啟動,就像任何其他服務一樣。
我的臨時解決方案是使用
ExecStopPost=/bin/rm /file/to/delete
但這不是解決問題的令人滿意的方法,因為它總是會在停止服務時刪除文件,無論是否因為失敗。
失敗時輸出:
● software.service - Software Loaded: loaded (/home/trippelganger/.config/systemd/user/software.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Fri 2018-05-04 09:05:26 CEST; 5s ago Process: 1839 ExecStart=/bin/run_program (code=exited, status=1/FAILURE) Main PID: 1839 (code=exited, status=1/FAILURE) May 04 09:05:26 trippelganger systemd[595]: software.service: Main process exited, code=exited, status=1/FAILURE May 04 09:05:26 trippelganger systemd[595]: software.service: Unit entered failed state. May 04 09:05:26 trippelganger systemd[595]: software.service: Failed with result 'exit-code'.
systemctl –user status software-fail.service 的輸出是:
● software-fail.service - Delete corrupt files Loaded: loaded (/home/trippelganger/.config/systemd/user/software-fail.service; disabled; vendor preset: enabled) Active: inactive (dead)
注意:您可能想使用
ExecStopPost=
而不是OnFailure=
此處(請參閱我的其他答案),但這是試圖解決您的OnFailure=
設置無法正常工作的原因。不啟動單元的問題
OnFailure=
可能是因為它在錯誤的部分,它需要在[Unit]
部分而不是[Service]
。你可以試試這個:
# software.service [Unit] Description=Software OnFailure=software-fail.service [Service] ExecStart=/bin/run_program
和:
# software-fail.service [Unit] Description=Delete corrupt files [Service] ExecStart=/bin/rm /file/to/delete ExecStop=/bin/systemctl --user start software.service
我可以讓它與這個設置一起工作。
但是請注意,
OnFailure=
在這裡使用並不理想,因為您無法真正說出程序失敗的原因,並且ExecStop=
通過直接呼叫來連結它的另一個開始/bin/systemctl start
是非常hacky……使用ExecStopPost=
和查看退出狀態的解決方案絕對是優越的。如果你定義
OnFailure=
inside[Service]
,systemd(至少來自 Fedora 27 的 234 版)會抱怨:software.service:6: Unknown lvalue 'OnFailure' in section 'Service'
不確定您是否在日誌中看到它……(也許這是在最近的 systemd 中添加的?)這應該暗示那裡發生了什麼。
為了在服務失敗時執行一些清理,您可以使用
ExecStopPost=
,無論服務成功與否都會執行。在您執行的程式碼中,
ExecStopPost=
您可以使用或之一來確定故障條件並採取相應措施。請參閱有關這些環境變數的文件以檢查哪個適合您。$SERVICE_RESULT``$EXIT_CODE``$EXIT_STATUS
然後您可以使用
Restart=on-failure
systemd 在失敗時嘗試重新啟動您的單元。把它們放在一起,這就是它的樣子。假設
run_program
只要文件損壞,它將以狀態 2 退出(希望您可以將其適應上述文件中的其他故障場景),這應該可以工作:[Service] ExecStart=/bin/run_program ExecStopPost=/bin/sh -c 'if [ "$$EXIT_STATUS" = 2 ]; then rm /file/to/delete; fi' Restart=on-failure
(注意:雙美元符號
$$
是將其轉義到 systemd,因此 shell 可以看到$EXIT_STATUS
並訪問該變數。使用單個美元符號也可以,但隨後 systemd 會進行替換,而 shell 會看到[ "2" = 2 ]
,這可以說是也可以…無論如何,您可以通過將所有這些邏輯放入一個shell腳本並通過其完整路徑呼叫它來繞過大部分,這ExecStopPost=
可能會更好,您還可以輕鬆地向腳本添加更多命令,例如記錄從錯誤情況中恢復所採取的操作。)希望這將為您提供足夠的指導,以了解如何根據您的特定情況正確配置它!