Linux

在 systemd 中使用 OnFailure 的正確方法

  • January 3, 2020

我有一個執行軟體的服務,如果它們不存在,它會生成一些配置文件,如果它們存在則讀取它們。我一直面臨的問題是這些文件有時會損壞,使軟體無法啟動,從而導致服務失敗。在這種情況下,我想刪除這些文件並重新啟動服務。

我嘗試通過執行以下操作創建一個在失敗時應該執行的服務:

[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-failuresystemd 在失敗時嘗試重新啟動您的單元。

把它們放在一起,這就是它的樣子。假設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=可能會更好,您還可以輕鬆地向腳本添加更多命令,例如記錄從錯誤情況中恢復所採取的操作。)

希望這將為您提供足夠的指導,以了解如何根據您的特定情況正確配置它!

引用自:https://unix.stackexchange.com/questions/441575