Ce face signal.NotifyContext
signal.NotifyContext combină semnalele cu context: contextul returnat se închide (ctx.Done()) la primul semnal din listă. Îl dai mai departe funcțiilor care acceptă context (servere HTTP, interogări de baze de date, exec.CommandContext) și toate se opresc ordonat la Ctrl+C.
Funcția stop anulează urmărirea semnalelor și redă comportamentul implicit; apeleaz-o cu defer stop(). După primul semnal, un al doilea Ctrl+C oprește programul abia după ce ai apelat stop. Din Go 1.26, context.Cause(ctx) spune ce semnal a fost primit.
Parametri
| Parametru | Descriere |
|---|---|
parent |
Contextul părinte, de obicei context.Background(). |
signals |
Semnalele care anulează contextul. |
Ce returnează
Contextul nou și funcția stop.
Exemple
Exemplul 1: Oprire ordonată a unei bucle de lucru
După 120 ms programul își trimite singur os.Interrupt, ca și cum utilizatorul ar apăsa Ctrl+C.
package main
import (
"context"
"fmt"
"os"
"os/signal"
"time"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
go func() {
time.Sleep(120 * time.Millisecond)
proces, _ := os.FindProcess(os.Getpid())
proces.Signal(os.Interrupt)
}()
lucrari := 0
for {
select {
case <-ctx.Done():
fmt.Println("oprire cerută:", context.Cause(ctx))
fmt.Println("a lucrat înainte de oprire:", lucrari > 0)
return
case <-time.After(50 * time.Millisecond):
lucrari++
}
}
}
Rezultat
oprire cerută: interrupt signal received
a lucrat înainte de oprire: true
Exemplul 2: Server HTTP oprit cu Ctrl+C
Model complet pentru un server real; nu rulează aici pentru că așteaptă conexiuni.
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
srv := &http.Server{Addr: ":8080"}
go func() {
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}()
log.Println("server pornit pe :8080")
<-ctx.Done()
log.Println("opresc serverul...")
ctxOprire, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
srv.Shutdown(ctxOprire)
log.Println("gata")
}
Rezultat în terminal (după Ctrl+C)
2025/03/14 10:00:00 server pornit pe :8080
^C2025/03/14 10:02:17 opresc serverul...
2025/03/14 10:02:17 gata
Greșeli frecvente
- Uiți
defer stop(). Semnalele rămân redirecționate și Ctrl+C nu mai oprește programul nici după ce ai terminat. - Folosești pentru oprirea serverului același context care tocmai a fost anulat.
Shutdownare nevoie de un context nou, cu timpul lui de grație.
Comenzi înrudite
signal.Notify: Trimite semnalele primite de program (Ctrl+C, SIGTERM) pe un canal, ca să le tratezi; Stop oprește trimiterea.exec.CommandContext: Ca exec.Command, dar procesul este oprit automat când contextul expiră sau este anulat.os.Exit: Oprește imediat programul cu codul de ieșire dat; funcțiile amânate cu defer nu mai rulează.