Quero capturar o sinal Ctrl+C( SIGINT
) enviado do console e imprimir alguns totais parciais de execução.
Isso é possível em Golang?
Nota: Quando publiquei a pergunta pela primeira vez, fiquei confuso sobre Ctrl+Cestar em SIGTERM
vez de SIGINT
.
Você pode usar o pacote os / signal para lidar com os sinais recebidos. Ctrl+ Cé SIGINT , então você pode usá-lo para interceptar os.Interrupt
.
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func(){
for sig := range c {
// sig is a ^C, handle it
}
}()
A maneira como você faz com que o seu programa encerre e imprima as informações é inteiramente sua.
for sig := range g {
, você também pode usar<-sigchan
como nesta resposta anterior: stackoverflow.com/questions/8403862/…go run
em um console e enviar um SIGTERM via ^ C, o sinal será gravado no canal e o programa responderá, mas parecerá sair inesperadamente do loop. Isso ocorre porque o SIGRERM também vaigo run
! (Isso tem me causa confusão substancial!)runtime.Gosched
em local apropriado (em loop principal do programa, se ele tiver um)Isso funciona:
fonte
Para adicionar um pouco às outras respostas, se você realmente deseja capturar o SIGTERM (o sinal padrão enviado pelo comando kill), pode usar
syscall.SIGTERM
no lugar do os.Interrupt. Cuidado que a interface syscall é específica do sistema e pode não funcionar em qualquer lugar (por exemplo, no Windows). Mas funciona bem para capturar os dois:fonte
signal.Notify
função permite especificar vários sinais ao mesmo tempo. Assim, você pode simplificar seu código parasignal.Notify(c, os.Interrupt, syscall.SIGTERM)
.os.Kill
corresponde asyscall.Kill
, que é um sinal que pode ser enviado, mas não capturado. É equivalente ao comandokill -9 <pid>
. Se você deseja capturarkill <pid>
e desligar normalmente, você deve usarsyscall.SIGTERM
.Havia (no momento da publicação) um ou dois pequenos erros de digitação na resposta aceita acima, então aqui está a versão limpa. Neste exemplo, paro o criador de perfil da CPU ao receber Ctrl+ C.
fonte
runtime.Gosched
em local apropriado (em loop principal do programa, se ele tiver um)Todas as opções acima parecem funcionar quando emendadas, mas a página de sinais do gobyexample tem um exemplo realmente limpo e completo de captura de sinal. Vale a pena adicionar a esta lista.
fonte
A morte é uma biblioteca simples que usa canais e um grupo de espera para aguardar sinais de desligamento. Depois que o sinal for recebido, ele chamará um método close em todas as suas estruturas que você deseja limpar.
fonte
Você pode ter uma goroutine diferente que detecte os sinais syscall.SIGINT e syscall.SIGTERM e retransmiti-los para um canal usando signal.Notify . Você pode enviar um gancho para essa goroutine usando um canal e salvá-lo em uma fatia de função. Quando o sinal de desligamento é detectado no canal, você pode executar essas funções na fatia. Isso pode ser usado para limpar os recursos, aguardar a conclusão de goroutines em execução, persistir dados ou imprimir totais parciais de execução.
Eu escrevi um utilitário pequeno e simples para adicionar e executar ganchos no desligamento. Espero que possa ser de ajuda.
https://github.com/ankit-arora/go-utils/blob/master/go-shutdown-hook/shutdown-hook.go
Você pode fazer isso de uma maneira "adiada".
exemplo para desligar um servidor normalmente:
fonte
Esta é outra versão que funciona caso você tenha algumas tarefas para limpar. O código deixará o processo de limpeza em seu método.
caso você precise limpar a função principal, você precisa capturar o sinal na thread principal usando go func () também.
fonte
Só para constar se alguém precisa de uma maneira de lidar com sinais no Windows. Eu tinha um requisito para lidar com prog A chamando prog B através de os / exec, mas prog B nunca foi capaz de terminar normalmente porque enviando sinais através de ex. O cmd.Process.Signal (syscall.SIGTERM) ou outros sinais não são suportados no Windows. A maneira como lidei com isso é criando um arquivo temporário como um sinal ex. .signal.term através de prog A e prog B precisa verificar se esse arquivo existe na base do intervalo; se existir, ele sairá do programa e executará uma limpeza, se necessário, tenho certeza de que existem outras maneiras, mas isso foi útil.
fonte