Last updated

🔗Signals

powpow provides two related things in signal.nim:

  1. SignalRelay — an in-process pub/sub event bus for named events.
  2. OS signal delivery — real OS signals (SIGINT, SIGTERM, SIGHUP, …) delivered through the event loop, without global signal handlers.

Runnable examples: examples/signal_bus.nim, examples/os_signals.nim.

🔗SignalRelay: the in-process event bus

SignalRelay is an opaque handle (its type is internal, but it is returned by the exported constructors). Events are addressed by an integer signal id; you can also use OsSignal values as ids.

let relay = newSignalRelay(loop, maxSignals = 64)

# permanent subscriber
let handle = relay.listen(42, proc() = echo "event 42 fired")

# one-shot subscriber — auto-removed after the first event
relay.listenOnce(43, proc() = echo "event 43 fired (once)")

relay.emit(42)     # both 42 and 43 fire
relay.emit(43)     # only 42 fires — 43 already unsubscribed

unlisten(handle)   # or unlisten manually

listen/listenOnce return a ListenerHandle; call unlisten(handle) to remove a subscriber early.

The examples/signal_bus.nim demo drives this from an HTTP endpoint (curl "http://localhost:9005/emit?signal=3").

🔗OS signals

watchOsSignal/watchOsSignals bridge real OS signals into the loop. Delivery is platform-native with no global signal handlers:

  • Linux: signalfd
  • macOS / BSD / POSIX: self-pipe
  • Windows: SetConsoleCtrlHandler (Ctrl+C)
let relay = newOsSignalRelay(loop)

relay.listen(SignalInt, proc() = echo "SIGINT — shutting down gracefully")
relay.listen(SignalTerm, proc() = echo "SIGTERM — shutting down gracefully")
relay.listen(SignalHup, proc() = echo "SIGHUP — reload config")

watchOsSignals(relay, [SignalInt, SignalTerm, SignalHup])
loop.run()

OsSignal enum:

ValueSignal
SignalHupSIGHUP
SignalIntSIGINT
SignalQuitSIGQUIT
SignalUsr1SIGUSR1
SignalUsr2SIGUSR2
SignalPipeSIGPIPE
SignalAlarmSIGALRM
SignalTermSIGTERM
SignalUrgentSIGURG
SignalChildSIGCHLD
SignalIoSIGIO

signalNumber(s: OsSignal): cint gives the raw platform number.

🔗Graceful shutdown pattern

relay.listen(SignalInt, proc() =
  server.stop()          # stop accepting
  loop.stop()            # stop the loop
  server.close()         # clean up after the loop has stopped
  loop.close())

See examples/os_signals.nim for this exact flow.

🔗API reference

Full signatures: signal API.