시스템 서비스가 다른 서비스를 다시 시작하도록 만드는 방법은 무엇입니까?

시스템 서비스가 다른 서비스를 다시 시작하도록 만드는 방법은 무엇입니까?

나는애플리케이션매일 유지 관리되는 시작 시 데이터베이스에서 읽습니다.별도의 업데이터, systemd다음 단위로 설명됩니다.

application.service:

[Unit]
Description=Application reading database
Wants=network-online.target
After=local-fs.target network-online.target nss-lookup.target

[Service]
User=application
Group=application
WorkingDirectory=/var/lib/application
ExecStart=/var/lib/application/application-exec --database /var/db/database.db
StandardOutput=file:/var/lib/application/application.stdout.log
StandardError=file:/var/lib/application/application.stderr.log

StartLimitInterval=60
StartLimitBurst=10
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

updater.service:

[Unit]
Description=Database updater
Wants=network-online.target
After=local-fs.target network-online.target nss-lookup.target

[Service]
Type=oneshot
User=updater
Group=updater
WorkingDirectory=/var/lib/updater
ExecStart=/var/lib/updater/updater-exec --database /var/db/database.db
StandardOutput=file:/var/lib/updater/updater.stdout.log
StandardError=file:/var/lib/updater/updater.stderr.log

[Install]
WantedBy=multi-user.target

updater.timer:

[Unit]
Description=Timer for database updater

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=900
Persistent=true

[Install]
WantedBy=timers.target

내 질문:

어떻게 만들 수 있나요?업데이트 서비스재시작응용 서비스업데이트가 성공적으로 실행되었습니까?(응용 프로그램이 현재 업데이트된 데이터베이스를 다시 읽습니다. 성공/실패는 업데이트 프로그램의 종료 코드로 표시됩니다.)

이 문제존재하다서버 장애비슷하지만 불행히도 내 사용 사례에 적합한 답변이 없습니다.

답변1

해결책은 예상보다 훨씬 간단했습니다. 다음 줄을 추가해야 합니다 updater.service.

ExecStartPost=+/usr/bin/systemctl restart application.service

결과 updater.service:

[Unit]
Description=Database updater
Wants=network-online.target
After=local-fs.target network-online.target nss-lookup.target

[Service]
Type=oneshot
User=updater
Group=updater
WorkingDirectory=/var/lib/updater
ExecStart=/var/lib/updater/updater-exec --database /var/db/database.db
StandardOutput=file:/var/lib/updater/updater.stdout.log
StandardError=file:/var/lib/updater/updater.stderr.log
ExecStartPost=+/usr/bin/systemctl restart application.service

[Install]
WantedBy=multi-user.target

관련 발췌 man 5 systemd.service:

├───────┼────────────────────────────────────────┤
│"+"    │ If the executable path is prefixed     │
│       │ with "+" then the process is executed  │
│       │ with full privileges. In this mode     │
│       │ privilege restrictions configured with │
│       │ User=, Group=, CapabilityBoundingSet=  │
│       │ or the various file system namespacing │
│       │ options (such as PrivateDevices=,      │
│       │ PrivateTmp=) are not applied to the    │
│       │ invoked command line (but still affect │
│       │ any other ExecStart=, ExecStop=, ...   │
│       │ lines).                                │
├───────┼────────────────────────────────────────┤
ExecStartPost= commands are only run after the commands specified in ExecStart= have been invoked
successfully, as determined by Type= (i.e. the process has been started for Type=simple or Type=idle,
the last ExecStart= process exited successfully for Type=oneshot, the initial process exited
successfully for Type=forking, "READY=1" is sent for Type=notify, or the BusName= has been taken for
Type=dbus).

설명하다:

  • ExecStartPost=이전 이유로 인해 명령은 루트 권한으로 실행됩니다 ( 첫 번째 발췌 참조 +) application.service.systemctlUser=Group=
  • ExecStartPost=성공한 경우에만 명령을 실행합니다 ExecStart=(두 번째 발췌 참조). 그러면 조건부 재시작이 허용됩니다.application.service

답변2

이것을 알아내는 것은 재미있었습니다!

세 번째 서비스를 혼합에 추가한 다음 및 사이의 종속성을 다음과 같이 restart-application.service정렬합니다 .restart-applicationserviceupdater.service

  • restart-application.service시작 하다updater.service
  • restart-application.serviceupdater.service완료될 때까지 실제로 실행되지 않습니다.
  • restart-application.serviceupdater.service성공하지 않으면 실행되지 않습니다.

우리는 restart-application.service이것을 다음과 같이 만듭니다:

[Unit]
Description=Restart application
BindsTo=updater.service
After=updater.service

[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl restart application

우리는BindsTo여기에 종속성이 있습니다. 문서의 주요 부분은 다음과 같습니다.

BindsTo=의 동작은 동일한 셀에서 After=와 함께 사용될 때 더욱 강력해집니다. 이 경우 엄격하게 바인딩된 유닛이 활성화되어야 하며, 이 유닛도 활성화됩니다.

이제 Unit부품을 updater.service다음과 같이 수정합니다.

[Unit]
Description=Database updater
Wants=network-online.target
After=local-fs.target network-online.target nss-lookup.target
StopWhenUnneeded=true

그리고 Service포함할 부분은 다음과 같습니다.

RemainAfterExit=true

이러한 변경은 (a) updater.service명령이 완료된 후에도 "활성" 상태로 유지된다는 것을 의미합니다. 이는 명령이 활성화된 경우에만 실행되기 ExecStart때문입니다 . restart-application.service이 옵션은 StopWhenUnneeded=true다른 어떤 것도 의존하지 않을 때(즉, 정지되었을 때 ) restart-application.service장치가 비활성화된다는 것을 의미합니다.

마지막으로 타이머가 restart-application.service대신 시작되도록 수정해야 합니다 updater.service.


application.service나는 (간단한 웹서버를 실행하는) 더미 와 updater.service무작위로 성공하거나 실패하는 더미를 만들었습니다.

[Unit]
Description=Database updater
Wants=network-online.target
After=local-fs.target network-online.target nss-lookup.target
StopWhenUnneeded=true

[Service]
Type=oneshot
User=updater
Group=updater
WorkingDirectory=/home/updater
ExecStart=/bin/bash -c 'rc=$(( RANDOM % 2 )); echo "rc=$rc"; exit $rc'
RemainAfterExit=true

로그를 살펴보겠습니다 systemctl start restart-application.service. updater.service실패하면 어떤 일이 발생합니까 ?

... systemd[1]: Starting updater.service - Database updater...
... bash[1253]: rc=1
... systemd[1]: updater.service: Main process exited, code=exited, status=1/FAILURE
... systemd[1]: updater.service: Failed with result 'exit-code'.
... systemd[1]: Failed to start updater.service - Database updater.
... systemd[1]: Dependency failed for restart-application.service - Restart application.
... systemd[1]: restart-application.service: Job restart-application.service/start failed with result 'dependency'.

updater.service성공하면 다음이 발생합니다.

... systemd[1]: Starting updater.service - Database updater...
... systemd[1]: Finished updater.service - Database updater.
... darkhttpd[1193]: darkhttpd/1.13, copyright (c) 2003-2021 Emil Mikulic.
... darkhttpd[1193]: listening on: http://0.0.0.0:8080/
... systemd[1]: Starting restart-application.service - Restart application...
... bash[1262]: rc=0
... systemd[1]: Stopping application.service - Application reading database...
... systemd[1]: application.service: Deactivated successfully.
... systemd[1]: Stopped application.service - Application reading database.
... systemd[1]: Started application.service - Application reading database.
... systemd[1]: restart-application.service: Deactivated successfully.
... systemd[1]: Finished restart-application.service - Restart application.
... systemd[1]: updater.service: Deactivated successfully.
... systemd[1]: Stopped updater.service - Database updater.

현재 모든 상황:

# systemctl status application.service updater.service restart-application.service
● application.service - Application reading database
     Loaded: loaded (/etc/systemd/system/application.service; disabled; vendor preset: disabled)
     Active: active (running) since Sat 2022-09-17 20:48:27 UTC; 1min 53s ago
   Main PID: 1264 (darkhttpd)
      Tasks: 1 (limit: 4661)
     Memory: 172.0K
        CPU: 1ms
     CGroup: /system.slice/application.service
             └─ 1264 /usr/sbin/darkhttpd /home/application/htdocs --port 8080

○ updater.service - Database updater
     Loaded: loaded (/etc/systemd/system/updater.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

○ restart-application.service - Restart application
     Loaded: loaded (/etc/systemd/system/restart-application.service; static)
     Active: inactive (dead)

나는 이것이 당신이 원하는 모든 것을 할 것이라고 생각합니다.

관련 정보