2015-08-25 13 views
9

Chcę odrodzić długotrwałe procesy potomne, które przetrwają, gdy główny proces zostanie ponownie uruchomiony/zginie. Działa to dobrze, gdy uruchomiony z terminala:Nie można odłączyć procesu potomnego, gdy główny proces jest uruchamiany z systemu

$ cat exectest.go 
package main 

import (
     "log" 
     "os" 
     "os/exec" 
     "syscall" 
     "time" 
) 

func main() { 
     if len(os.Args) == 2 && os.Args[1] == "child" { 
       for { 
         time.Sleep(time.Second) 
       } 
     } else { 
       cmd := exec.Command(os.Args[0], "child") 
       cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} 
       log.Printf("child exited: %v", cmd.Run()) 
     } 
} 
$ go build 
$ ./exectest 
^Z 
[1]+ Stopped     ./exectest 
$ bg 
[1]+ ./exectest & 
$ ps -ef | grep exectest | grep -v grep | grep -v vim 
snowm  7914 5650 0 23:44 pts/7 00:00:00 ./exectest 
snowm  7916 7914 0 23:44 ?  00:00:00 ./exectest child 
$ kill -INT 7914 # kill parent process 
[1]+ Exit 2     ./exectest 
$ ps -ef | grep exectest | grep -v grep | grep -v vim 
snowm  7916  1 0 23:44 ?  00:00:00 ./exectest child 

pamiętać, że proces dziecko nadal żyje po proces nadrzędny został zabity. Jednakże, jeśli zacznę główny proces od Systemd tak ...

[[email protected]localhost exectest]$ cat /etc/systemd/system/exectest.service 
[Unit] 
Description=ExecTest 

[Service]       
Type=simple 
ExecStart=/home/snowm/src/exectest/exectest 
User=snowm 

[Install] 
WantedBy=multi-user.target 
$ sudo systemctl enable exectest 
ln -s '/etc/systemd/system/exectest.service' '/etc/systemd/system/multi-user.target.wants/exectest.service' 
$ sudo systemctl start exectest 

... to dziecko umiera także kiedy zabić głównego procesu:

$ ps -ef | grep exectest | grep -v grep | grep -v vim 
snowm  8132  1 0 23:55 ?  00:00:00 /home/snowm/src/exectest/exectest 
snowm  8134 8132 0 23:55 ?  00:00:00 /home/snowm/src/exectest/exectest child 
$ kill -INT 8132 
$ ps -ef | grep exectest | grep -v grep | grep -v vim 
$ 

Jak mogę sprawić dziecku przetrwać?

Działająca wersja go1.4.2 linux/amd64 w wersji CentOS Linux 7.1.1503 (Core).

+0

SystemD prawdopodobnie zabija wszystko w grupie procesów (lub cgroup, od jakiegoś czasu nie patrzyłem na systemd). Czy faktycznie próbujesz emulować zachowanie demona, czy jest to tylko przykład? – JimB

+0

@ JimB: Mój rzeczywisty kod odradza procesy potomne, które uruchamiają ffmpeg. Zasadniczo używam powyższego wzorca do emulowania zachowania demona, tak. –

+0

Dlaczego nie zostawić rodzica działającego i pozwolić systemdowi zarządzać nim normalnie? Myślę, że może być sposób na odrodzenie dziecka i powiadomienie systemu o nowym procesie, ale ten pierwszy byłby znacznie łatwiejszy. – JimB

Odpowiedz

13

rozwiązaniem jest dodanie

KillMode=process 

do bloku serwisowego. Domyślna wartość to control-group, co oznacza, że ​​systemd czyści wszystkie procesy podrzędne.

Od man systemd.kill

KillMode = Określa, w jaki sposób procesy tego urządzenia powinien zostać zabity. Jedna z grup kontrolnych , proces, mieszany, brak.

Jeśli ustawiony na sterowanie-Group, wszystkie pozostałe procesy w grupie kontrolnej tej jednostki zostanie zabity na przystanku jednostkowej (dla usługi: po zatrzymaniu komenda jest wykonywana, jak skonfigurowany ExecStop =). Jeśli ustawione do przetwarzania, tylko główny proces jest zabijany. Jeśli jest ustawiony na mieszanie, sygnał SIGTERM (patrz poniżej) jest wysyłany do głównego procesu, a kolejny sygnał SIGKILL (patrz poniżej) jest wysyłany do wszystkich pozostałych procesów w grupie kontrolnej jednostki . Jeśli ma wartość none, żaden proces nie zostanie zabity. W tym przypadku tylko polecenie zatrzymania zostanie wykonane na zatrzymaniu jednostki, ale w przeciwnym przypadku proces nie zostanie zabity. Procesy pozostające przy życiu po zatrzymaniu są pozostawione w ich grupie kontrolnej, a grupa kontrolna po zatrzymaniu nadal istnieje , chyba że jest pusta.

+0

Czy zamiast tego istnieje sposób na przeniesienie procesu z grupy? –