저는 systemd 단위 파일을 사용하여 서버에서 실행되는 Python 프로세스를 제어합니다(systemd v247 사용).
이 프로세스는 600초 내에 5번 실패하지 않는 한 실패 여부에 관계없이 종료 후 60초 후에 다시 시작해야 합니다.
이 유닛 파일은 이메일을 통한 장애 알림을 위해 다른 서비스에 연결됩니다.
/etc/systemd/system/python-test.service
[Unit]
After=network.target
OnFailure=mailer@%n.service
[Service]
Type=simple
ExecStart=/home/debian/tmp.py
# Any exit status different than 0 is considered as an error
SuccessExitStatus=0
StandardOutput=append:/var/log/python-test.log
StandardError=append:/var/log/python-test.log
# Always restart service 60sec after exit
Restart=always
RestartSec=60
# Stop restarting service after 5 consecutive fail in 600sec interval
StartLimitInterval=600
StartLimitBurst=5
[Install]
WantedBy=multi-user.target
/etc/systemd/system/[email protected]
[Unit]
After=network.target
[Service]
Type=oneshot
ExecStart=/home/debian/mailer.py --to "[email protected]" --subject "Systemd service %I failed" --message "A systemd service failed %I on %H"
[Install]
WantedBy=multi-user.target
OnFailure
기본 테스트 중에 트리거가 매우 잘 작동했습니다. 하지만 유닛 파일에 다음 섹션을 추가하면 OnFailure
5번 연속 실패가 발생할 때만 실행됩니다.
StartLimitInterval=600
StartLimitBurst=5
아직 버스트 제한에 도달하지 않았더라도 프로세스가 실패할 때마다 알림을 받고 싶기 때문에 이는 내가 원하는 동작이 아닙니다.
프로세스 상태를 확인할 때 버스트 제한에 도달하지 않은 경우 출력이 다릅니다.
● python-test.service
Loaded: loaded (/etc/systemd/system/python-test.service; disabled; vendor preset: enabled)
Active: activating (auto-restart) (Result: exit-code) since Thu 2022-12-22 19:51:23 UTC; 2s ago
Process: 1421600 ExecStart=/home/debian/tmp.py (code=exited, status=1/FAILURE)
Main PID: 1421600 (code=exited, status=1/FAILURE)
CPU: 31ms
Dec 22 19:51:23 test-vps systemd[1]: python-test.service: Failed with result 'exit-code'.
그때보다
● python-test.service
Loaded: loaded (/etc/systemd/system/python-test.service; disabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Thu 2022-12-22 19:52:02 UTC; 24s ago
Process: 1421609 ExecStart=/home/debian/tmp.py (code=exited, status=1/FAILURE)
Main PID: 1421609 (code=exited, status=1/FAILURE)
CPU: 31ms
Dec 22 19:51:56 test-vps systemd[1]: python-test.service: Failed with result 'exit-code'.
Dec 22 19:52:02 test-vps systemd[1]: python-test.service: Scheduled restart job, restart counter is at 5.
Dec 22 19:52:02 test-vps systemd[1]: Stopped python-test.service.
Dec 22 19:52:02 test-vps systemd[1]: python-test.service: Start request repeated too quickly.
Dec 22 19:52:02 test-vps systemd[1]: python-test.service: Failed with result 'exit-code'.
Dec 22 19:52:02 test-vps systemd[1]: Failed to start python-test.service.
Dec 22 19:52:02 test-vps systemd[1]: python-test.service: Triggering OnFailure= dependencies.
OnFailure
유닛 파일 내에서 트리거를 수정하는 방법을 설명하는 내용을 찾을 수 없습니다 .
프로세스가 실패할 때마다 이메일로 알리면서도 버스트 제한을 유지하는 방법이 있습니까?
답변1
시스템 서비스를 필요에 맞게 이용하기 위해서는 몇 가지 작업을 수행해야 합니다. (변경 진행 중)/etc/systemd/system/python-test.service).
Restart=always
로 변경Restart=on-failure
- 이 값 도 지원되는
StartLimitInterval=600
것으로 보입니다 .StartLimitBurst=5
하지만 에 넣어야 합니다 . 를[Unit]
넣으면 이름을 바꿀 수 있습니다 ( 대신 사용 ).StartLimitInterval
[Unit]
StartLimitIntervalSec
man systemd.unit
StartLimitIntervalSec
RemainAfterExit=no
섹션 에 추가하세요[Service]
.- 섹션에 다음 줄을 추가하세요
[Service]
.TimeoutStopSec=infinity
- 스크립트의 환경 변수를 사용하여
EXIT_STATUS
스크립트가 성공적으로 종료되었는지 확인합니다. - 로 변경 .
OnFailure=mailer@%n.service
둘OnFailure=mailer@%N.service
의 차이점은 이를 사용하면%N
접미사가 삭제된다는 점입니다. - 명령을 사용할 수 있도록 서비스
atd
( )를 설치하고 시작합니다. 또는 사용하지 않으려면 다른 시스템 서비스를 작성하여 서비스를 다시 시작할 수 있습니다. (이 예에서는 를 사용했습니다 )sudo systemctl start atd.service
at
at
relaunch.service
sleep
및 에 동일한 값을 사용하십시오RestartSec
. 귀하의 경우에는 이 줄RestartSec
에서 수면 도 다음을 포함해야 합니다.60
60
echo "sleep 60; sudo systemctl start ${1}.service" | at now
- 사용
ExecStart
하고ExecStopPost=
획득종료 상태주요 프로세스:/home/debian/tmp.py
.ExecStop
다음에서 을(를) 사용하지 마십시오man systemd.service
:
실행이 중지됨 =
ExecStop=에 지정된 명령은 서비스가 처음으로 성공적으로 시작될 때만 실행됩니다. 서비스가 전혀 시작된 적이 없거나 시작에 실패한 경우(예: ExecStart=, ExecStartPre= 또는 ExecStartPost=에 지정된 명령이 실패했기 때문에) 호출되지 않습니다("-" 접두사가 붙지 않았습니다. 위 참조). ) 또는 시간이 초과되었습니다. 서비스가 올바르게 시작되지 않고 다시 종료되면 ExecStopPost=와 함께 명령이 호출됩니다.
제공하다/etc/systemd/system/python-test.service해야 한다:
[Unit]
After=network.target
OnFailure=mailer@%N.service
StartLimitBurst=5
StartLimitIntervalSec=600
[Service]
Type=simple
TimeoutStopSec=infinity
ExecStart=/home/debian/tmp.py
ExecStopPost=/bin/bash -c 'echo The Service has exited with values: $$EXIT_STATUS,$$SERVICE_RESULT,$$EXIT_CODE'
ExecStopPost=/home/debian/bin/checkSuccess "%N"
# Any exit status different than 0 is considered as an error
SuccessExitStatus=0
StandardOutput=append:/tmp/python-out-test.log
StandardError=append:/tmp/python-err-test.log
# Always restart service 60sec after exit
Restart=on-failure
RestartSec=60
RemainAfterExit=no
[Install]
WantedBy=multi-user.target
그리고/홈/데비안/bin/checkSuccess다음이 있어야 합니다.
해결 방법 1:사용 at
명령:
#!/bin/bash
if [ "$EXIT_STATUS" -eq 0 ]
then
echo "sleep 60; sudo systemctl start ${1}.service" | at now
exit 0
else
systemctl start "mailer@${1}.service"
exit 0
fi
해결 방법 2:다른 시스템 서비스를 사용하십시오.
#!/bin/bash
if [ "$EXIT_STATUS" -eq 0 ]
then
systemctl start relaunch.service
else
systemctl start "mailer@${1}.service"
fi
exit 0
그리고 relaunch.service
다음이 있어야 합니다:
[Unit]
Description=Relaunch Python Test Service
[Service]
Type=simple
RemainAfterExit=no
ExecStart=/bin/bash -c 'echo Delay; sleep 10 ; systemctl start python-test.service'
"$EXIT_STATUS"
systemd 서비스에 의해 설정된 변수는 종료 상태에 따라 결정됩니다 /home/debian/tmp.py
.
${1}
단위를 나타내는 이름: python-test
라인의 스크립트에 전달합니다 /home/debian/bin/checkSuccess "%N"
.
노트:
'echo The Service %n has exited with values: $$EXIT_STATUS,$$SERVICE_RESULT,$$EXIT_CODE'
다음 명령어를 사용하면 실시간으로 로그를 확인할 수 있습니다.
tail -f /tmp/python-out-test.log
relaunch.service
기본 서비스를 중지하려면 솔루션 2( with )를 사용하는 경우 다음을 실행해야 합니다.
sudo systemctl stop relaunch.service
#Might not be necessary but you stop python service too:
# sudo systemctl stop python-test.service