all repos — llm_aggregator @ 2d9899ec7612acc35f5ae4e343d6364a9f2dc8b1

A CLI tool to aggregate RSS feeds and summarise them with LLMs

internal/signals/signals.go (view raw)

 1// Package signals provides cross-platform signal handling for graceful shutdown.
 2package signals
 3
 4import (
 5	"os"
 6	"os/signal"
 7	"sync/atomic"
 8	"syscall"
 9)
10
11// Signals watched for graceful shutdown.
12var (
13	SigInt  = os.Signal(syscall.SIGINT)
14	SigTerm = os.Signal(syscall.SIGTERM)
15	SigHup  = os.Signal(syscall.SIGHUP)
16)
17
18// SignalHandler coordinates signal watching and exit requests.
19type SignalHandler struct {
20	notify  chan os.Signal
21	done    chan struct{}
22	exiting atomic.Bool
23}
24
25// New creates a new SignalHandler.
26func New() *SignalHandler {
27	return &SignalHandler{
28		notify: make(chan os.Signal, 1),
29		done:   make(chan struct{}),
30	}
31}
32
33// Watch starts the signal listener goroutine and returns immediately.
34// The goroutine exits cleanly when Stop() is called.
35func (sh *SignalHandler) Watch() {
36	signal.Notify(sh.notify, SigInt, SigTerm, SigHup)
37	go func() {
38		select {
39		case <-sh.notify:
40			sh.exiting.Store(true)
41		case <-sh.done:
42			return
43		}
44	}()
45}
46
47// IsExiting returns true if an exit has been requested (by signal).
48func (sh *SignalHandler) IsExiting() bool {
49	return sh.exiting.Load()
50}
51
52// Stop stops signal watching. The Watch() goroutine exits immediately.
53// Safe to call from any goroutine, including signal handlers.
54func (sh *SignalHandler) Stop() {
55	signal.Stop(sh.notify)
56	select {
57	case sh.done <- struct{}{}:
58	default:
59	}
60}