web-dev-qa-db-fra.com

Signaux de capture de Golang

Je veux implémenter un "wrapper de processus" dans Go. Fondamentalement, il va lancer un processus (disons un serveur de nœuds) et le surveiller (capturer des signaux comme SIGKILL, SIGTERM ...)

Je pense que la façon de faire est de lancer le serveur de noeud dans une routine go en utilisant syscall.Exec:

func launchCmd(path string, args []string) {
  err := syscall.Exec(path, args, os.Environ())
  if err != nil {
    panic(err)
  }
}

Ensuite, je voudrais attraper tous les signaux possibles générés par la commande exécutée par syscall. Je suis assez nouveau pour Go, toute aide serait appréciée.

20
rmonjo

Il existe trois façons d'exécuter un programme dans Go:

  1. syscall package avec syscall.Exec , syscall.ForkExec , syscall.StartProcess
  2. os package avec os.StartProcess
  3. os/exec package avec exec.Command

syscall.StartProcess est de bas niveau. Il renvoie un uintptr comme un handle.

os.StartProcess vous donne une belle os.Process struct que vous pouvez appeler Signal activé. os/exec vous donne io.ReaderWriter à utiliser sur un tuyau. Les deux utilisent syscall en interne.

La lecture des signaux envoyés depuis un processus autre que le vôtre semble un peu délicat. Si c'était possible, syscall serait en mesure de le faire. Je ne vois rien d'évident dans les packages de niveau supérieur.

Pour recevoir un signal, vous pouvez utiliser signal.Notify comme ceci:

sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
    syscall.SIGHUP,
    syscall.SIGINT,
    syscall.SIGTERM,
    syscall.SIGQUIT)
go func() {
    s := <-sigc
    // ... do something ...
}()

Il vous suffit de changer les signaux que vous souhaitez écouter. Si vous ne spécifiez pas de signal, il captera tous les signaux pouvant être capturés.

Vous utiliseriez syscall.Kill ou Process.Signal pour mapper le signal. Vous pouvez obtenir le pid de Process.Pid ou à la suite de syscall.StartProcess .

45
Luke

Vous pouvez utiliser signal.Notify :

import (
"os"
"os/signal"
"syscall"
)

func main() {
    signalChannel := make(chan os.Signal, 2)
    signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
    go func() {
        sig := <-signalChannel
        switch sig {
        case os.Interrupt:
            //handle SIGINT
        case syscall.SIGTERM:
            //handle SIGTERM
        }
    }()
    // ...
}
22
Baba