Jak zatrzymać wszystkie procesy potomne odradzane przez usługę

6

Mam usługę działającą w systemie Ubuntu z następującą konfiguracją:

#/etc/init/my_service.conf

start on (local-filesystems and net-device-up IFACE=eth1)

respawn

exec python -u /opt/XYZ/my_prog.py 2>&1 \
                 | logger -t my_prog.py

Po zatrzymaniu usługi za sudo service my_service stoppomocą procesu python nie jest zabijany. Zabicie procesu nadrzędnego za pomocą killrównież nie zabija procesu Pythona.

Jak całkowicie zatrzymać usługę (tzn. Zabić wszystkie procesy potomne)? Idealnie nie chciałbym modyfikować powyższego pliku konfiguracyjnego.

Dhara
źródło

Odpowiedzi:

5

Idealnie nie chciałbym modyfikować powyższego pliku konfiguracyjnego.

Twardy! To jest właściwe.

Musisz zmienić swój execna scripti przestać uruchamiać ten program python w rozwidlonym podprocesie jako część potoku. Ta odpowiedź ServerFault wyjaśnia, jak to zrobić we wbudowanym skrypcie powłoki. Wprowadziłbym tylko jedną zmianę do podanego tam skryptu, w ostatnim wierszu:

exec python -u /opt/XYZ/my_prog.py 2>&1

W końcu nie ma naprawdę dobrego powodu, aby nie rejestrować standardowych błędów.

Coraz bardziej skomplikowane wahania, aby poradzić sobie z rozwidleniem, od expect daemonprzejścia do systemd, pomijają punkt, w którym właściwym rozwiązaniem jest powstrzymanie demona przed rozwidleniem . Jeśli z obecnej kerfuffli jest jedna dobra rzecz, jest to ciągłe potwierdzenie, że to, co IBM napisał i zalecił w 1995 roku, było słuszne przez te wszystkie lata.

Przyzwyczaj się do idei demonów ładujących łańcuch . Istnieje wiele zestawów narzędzi, które upraszczają takie rzeczy. Przyzwyczaj się również do tego, aby nie używać skryptów powłoki. Istnieje wiele zestawów narzędzi zaprojektowanych specjalnie do tej pracy, które eliminują narzuty powłok ( co jest znanym dobrym pomysłem w świecie Ubuntu ).

Na przykład: polecenia powłoki w odpowiedzi ServerFault można zastąpić skryptem, który korzysta z execlinenarzędzi Laurenta Bercota, które zostały zaprojektowane tak, aby móc to zrobić bez podpowłoki i niepowiązanych FIFO:

#!/command/execlineb -PW
pipeline -w {
    logger -t my_prog.py
} 
fdmove -c 2 1 
python -u /opt/XYZ/my_prog.py

co byś wtedy po prostu

exec /foo/this_execlineb_script

Z moim noshzestawem narzędzi podobnie byłby skrypt zawierający:

#!/usr/local/bin/nosh
pipe 
fdmove -c 2 1 
python -u /opt/XYZ/my_prog.py | logger -t my_prog.py

Lub alternatywnie, można mieć tę zwrotkę bezpośrednio w definicji zadania Upstart (używając sztuczki, aby uniknąć metaznaków powłoki, aby Upstart nie spawnował powłoki):

exec /usr/local/bin/exec pipe --separator SPLIT fdmove -c 2 1 python -u /opt/XYZ/my_prog.py SPLIT logger -t my_prog.py

Dalsza lektura

JdeBP
źródło
3

W GNU / Linux zwykle nie ma możliwości zatrzymania usługi i wszystkich procesów potomnych, które się ona pojawiła, ponieważ procesy potomne mogą zmienić swój PPID (identyfikator procesu nadrzędnego). Jedynym sposobem, aby to wiedzieć, jest śledzenie wywołań systemowych do odradzania procesów w trakcie ich tworzenia oraz prowadzenie listy tych procesów.

System inicjujący Ubuntu upstartnie robi tego. Więc odpowiedź na twoje pytanie jest niemożliwa - na Ubuntu - bez:

  1. Modyfikacja tego skryptu;
  2. Wiedząc dokładnie, które identyfikatory procesu są tworzone przez ten proces;
  3. Ręczne śledzenie tych identyfikatorów procesów;
  4. Zabijanie ich indywidualnie.

Dlatego powinieneś uruchomić dystrybucję Linuksa, która działa systemd . Jak widać, systemd śledzi wszystkie procesy potomne i może zabić każdy z nich za pomocą jednego polecenia. Tak powinna wyglądać administracja systemem GNU / Linux , ale ponieważ systemd jest tak nowy, a ponieważ nie został tutaj wymyślony (co oznacza, że ​​Canonical go nie wynalazł), Ubuntu nie chce go używać.

allquixotic
źródło
1
Upstart wysyła SIGTERM do całej grupy procesów, która domyślnie obejmie wszystkie procesy potomne odradzane przez proces główny. Tak więc, mimo że masz rację, nie możesz zagwarantować tego zachowania, chyba że kod wyraźnie zmieni identyfikator grupy procesów, zabije wszystkie dzieci.
Derek
1

Pominąłeś oczekiwany zwrotkę. Nowa książka kucharska określa:

Ostrzeżenie

Ta zwrotka jest niezwykle ważna: przeczytaj uważnie ten rozdział!

Upstart będzie śledził identyfikator procesu, który jego zdaniem należy do zadania. Jeśli zadanie określiło sekcję wystąpienia, Upstart będzie śledzić PID dla każdego unikalnego wystąpienia tego zadania.

Jeśli nie określisz oczekiwanej sekcji, Upstart będzie śledzić cykl życia pierwszego PID, który wykonuje w sekcjach exec lub skryptowych. Jednak większość usług uniksowych „demonizuje”, co oznacza, że ​​utworzą nowy proces (za pomocą fork (2)), który jest potomkiem procesu początkowego. Często usługi „podwójnie rozwidlają”, aby upewnić się, że nie mają żadnego związku z początkowym procesem. (Uwaga: początkowo żadne usługi nie rozwidlają się więcej niż dwa razy, ponieważ nie ma w tym dodatkowych korzyści).

W takim przypadku Upstart musi mieć sposób na jego wyśledzenie, abyś mógł użyć funkcji expect fork lub oczekiwanego demona, który pozwala Upstart na użycie polecenia ptrace (2) do „liczenia widelców”.

Aby Upstart mógł określić ostateczny identyfikator procesu dla zadania, musi wiedzieć, ile razy ten proces wywoła fork (2). Sam Upstart nie może znać odpowiedzi na to pytanie, ponieważ po uruchomieniu demona może rozwidlić wiele procesów „roboczych”, które same mogą rozwidlić dowolną liczbę razy. Nie można oczekiwać, że Upstart będzie wiedział, który PID jest „głównym” w tym przypadku, ponieważ nie wiadomo, czy procesy robocze zostaną w ogóle utworzone, nie mówiąc już o tym, ile razy lub ile razy proces rozwinie się na początku. W związku z tym konieczne jest poinformowanie Upstart, który PID jest „głównym” lub nadrzędnym PID. Osiąga się to za pomocą zwrotki oczekiwanie.

Potrzebujesz tego, ponieważ |używany potok tworzy procesy potomne. W książce Advanced Linux programowanie można znaleźć krótkie wprowadzenie do tego, w którym stwierdzono, że:

Na przykład to polecenie powłoki powoduje, że powłoka produkuje dwa procesy potomne, jeden dla ls i jeden dla mniej :

 $ ls | less

Nie wiem, czy oznacza to jeden czy dwa widelce, więc eksperymentowałbym ze zmodyfikowaniem odrodzenia linii w twoim kodzie za pomocą

 expect fork
 respawn

lub

 expect daemon
 respawn

Nie sądzę, że można to osiągnąć tylko dzięki systemd , chociaż moje logo wyraźnie pokazuje, że jestem fanem systemd .

MariusMatutiae
źródło
Z systemdjednym nie byłoby zatrudnienie loggerw pierwszej kolejności. Standardowe dane wyjściowe i błędy można przesyłać bezpośrednio do dziennika; nie wymaga podprocesów ani potoku w definicji usługi.
JdeBP
@JdeBP Nie kłócę się z systemd, po prostu mówię, o co prosi OP, można zrobić nawet na systemach (Ubuntu), w których go nie ma.
MariusMatutiae
Ale to całkowicie wstecz. Pytający pyta o to, jak coś z tym zrobić upstart; i za zwrócenie systemdna nią, a potem mówią, że może nawet być wykonane bez systemd wkłada wózek całkowicie przed koniem. To nie jest coś, z czym rozsądnie by się zrobiło systemd. Więc podkreślając, że może nawet być wykonane bez systemd jest w najlepszym wypadku dziwne. Poza tym nie jest to stanowcze. Jest to raczej zasadnicza część pytania.
JdeBP
@JdeBP J, twoje komentarze są zawsze tak niecodzienne , że stają się męczące. Wspomniałem o systemd tylko dlatego, że zrobił to allquixotic. Moja odpowiedź dotyczy przede wszystkim upstartu. Ponownie wywołałeś systemd. Jeśli chcesz podjąć zwykłą bezsensowną walkę, idź porozmawiać z kimś innym, już się nudzę
MariusMatutiae