Signals in Clojure
Here’s the translation of the Go code to Clojure, with explanations in Markdown format suitable for Hugo:
Clojure provides ways to handle Unix signals, allowing programs to gracefully respond to external events. Here’s how to handle signals in Clojure using core.async channels.
(ns signals-example
(:require [clojure.core.async :as async])
(:import (sun.misc Signal SignalHandler)))
(defn signal-handler [signal done-chan]
(reify SignalHandler
(handle [_ sig]
(println)
(println (.getName sig))
(async/>!! done-chan true))))
(defn main []
(let [done-chan (async/chan 1)]
; Register signal handlers for SIGINT and SIGTERM
(Signal/handle (Signal. "INT") (signal-handler "SIGINT" done-chan))
(Signal/handle (Signal. "TERM") (signal-handler "SIGTERM" done-chan))
; This could be done in the main thread, but we'll use a separate thread
; to demonstrate a more realistic scenario of graceful shutdown.
(async/thread
(println "awaiting signal")
(async/<!! done-chan)
(println "exiting"))))
(main)
In this Clojure version:
We use the
sun.misc.Signal
andsun.misc.SignalHandler
classes to handle Unix signals, as Clojure doesn’t have built-in signal handling.We create a
signal-handler
function that implements theSignalHandler
interface. It prints the signal name and sends a value on thedone-chan
channel.In the
main
function, we create a channeldone-chan
to communicate between the signal handler and the main thread.We register signal handlers for SIGINT and SIGTERM using
Signal/handle
.We use
async/thread
to start a separate thread that waits for a signal. This is similar to using a goroutine in Go.The program blocks on
(async/<!! done-chan)
, waiting for a signal. When a signal is received, it prints “exiting” and the program terminates.
To run this program:
$ clj signals_example.clj
awaiting signal
^C
INT
exiting
When we run this program, it will block waiting for a signal. By typing ctrl-C
, we can send a SIGINT signal, causing the program to print “INT” and then exit.
Note that Clojure’s approach to signal handling is somewhat different from Go’s. In Clojure, we’re using Java’s underlying signal handling mechanism, which doesn’t provide as clean an interface as Go’s os/signal
package. However, this approach achieves similar functionality.