Chcę przechwycić sygnał Ctrl+C( SIGINT
) wysłany z konsoli i wydrukować niektóre podsumowania częściowego uruchomienia.
Czy to możliwe w Golang?
Uwaga: Kiedy po raz pierwszy opublikowałem pytanie, byłem zdezorientowany, Ctrl+Cże jestem SIGTERM
zamiast SIGINT
.
for sig := range g {
możesz również użyć,<-sigchan
jak w poprzedniej odpowiedzi: stackoverflow.com/questions/8403862/...go run
pomocą konsoli i wyślesz SIGTERM przez ^ C, sygnał zostanie zapisany w kanale i program zareaguje, ale wydaje się, że niespodziewanie wypada z pętli. Dzieje się tak, ponieważ SIGRERM również się do tego nadajego run
! (To spowodowało poważne zamieszanie!)runtime.Gosched
w odpowiednim miejscu (w głównej pętli twojego programu, jeśli ma taką)To działa:
źródło
Aby dodać nieco do innych odpowiedzi, jeśli faktycznie chcesz złapać SIGTERM (domyślny sygnał wysyłany przez polecenie kill), możesz użyć
syscall.SIGTERM
zamiast OS.Interrupt. Uwaga: interfejs syscall jest specyficzny dla systemu i może nie działać wszędzie (np. W systemie Windows). Ale ładnie działa, aby złapać oba:źródło
signal.Notify
Funkcja pozwala określić kilka sygnałów jednocześnie. W ten sposób możesz uprościć swój kodsignal.Notify(c, os.Interrupt, syscall.SIGTERM)
.os.Kill
odpowiada sięsyscall.Kill
, co jest sygnałem, że może być wysłana, ale nie złapać. Jest to odpowiednik poleceniakill -9 <pid>
. Jeśli chcesz złapaćkill <pid>
i z wdziękiem zamknąć, musisz użyćsyscall.SIGTERM
.W przyjętej odpowiedzi powyżej była (w momencie publikacji) jedna lub dwie małe literówki, więc oto wyczyszczona wersja. W tym przykładzie zatrzymuję profilowanie procesora podczas odbierania Ctrl+ C.
źródło
runtime.Gosched
w odpowiednim miejscu (w głównej pętli twojego programu, jeśli ma taką)Wszystkie powyższe wydają się działać po połączeniu, ale strona sygnałów gobyexample ma naprawdę czysty i kompletny przykład przechwytywania sygnału. Warto dodać do tej listy.
źródło
Śmierć to prosta biblioteka, która korzysta z kanałów i grupy oczekiwania do oczekiwania na sygnały zamknięcia. Po odebraniu sygnału wywoła metodę close na wszystkich twoich strukturach, które chcesz oczyścić.
źródło
Możesz mieć inną goroutine, która wykrywa sygnały syscall.SIGINT i syscall.SIGTERM i przekazuje je do kanału za pomocą sygnału . Możesz wysłać hak do tego goroutine za pomocą kanału i zapisać go w wycinku funkcji. Po wykryciu sygnału wyłączenia na kanale można wykonać te funkcje w wycinku. Można to wykorzystać do czyszczenia zasobów, oczekiwania na zakończenie działania goroutyn, utrwalania danych lub drukowania sum częściowych przebiegów.
Napisałem małe i proste narzędzie do dodawania i uruchamiania haków przy zamykaniu systemu. Mam nadzieję, że to może pomóc.
https://github.com/ankit-arora/go-utils/blob/master/go-shutdown-hook/shutdown-hook.go
Możesz to zrobić w odroczony sposób.
przykład płynnego zamknięcia serwera:
źródło
To kolejna wersja, która działa w przypadku, gdy masz jakieś zadania do wyczyszczenia. Kod pozostawi proces czyszczenia w swojej metodzie.
na wypadek, gdybyś musiał wyczyścić główną funkcję, musisz przechwycić sygnał w głównym wątku za pomocą go func ().
źródło
Dla przypomnienia, jeśli ktoś potrzebuje sposobu na obsługę sygnałów w systemie Windows. Miałem wymóg obsługi z prog A wywołującego prog B przez os / exec, ale prog B nigdy nie był w stanie zakończyć z wdziękiem, ponieważ wysyłał sygnały przez ex. cmd.Process.Signal (syscall.SIGTERM) lub inne sygnały nie są obsługiwane w systemie Windows. Sposób, w jaki sobie poradziłem, to utworzenie pliku tymczasowego jako sygnału ex. .signal.term przez prog A i prog B musi sprawdzić, czy plik istnieje w odstępach czasowych, jeśli plik istnieje, opuści program i w razie potrzeby zajmie się czyszczeniem, jestem pewien, że istnieją inne sposoby, ale to zadziałało.
źródło