Signals in Crystal
Here’s the translation of the Go code to Crystal, formatted in Markdown suitable for Hugo:
Our first example demonstrates how to handle Unix signals in Crystal. This is useful for scenarios like gracefully shutting down a server when it receives a SIGTERM
, or stopping a command-line tool from processing input when it receives a SIGINT
.
require "signal"
# Create a channel to receive signal notifications
sigs = Channel(Signal).new(1)
# Register the channel to receive notifications for SIGINT and SIGTERM
Signal::INT.trap do
sigs.send(Signal::INT)
end
Signal::TERM.trap do
sigs.send(Signal::TERM)
end
# Create a channel to notify when we're done
done = Channel(Bool).new(1)
# This fiber executes a blocking receive for signals
# When it gets one, it'll print it out and then notify the program that it can finish
spawn do
sig = sigs.receive
puts
puts sig
done.send(true)
end
# The program will wait here until it gets the expected signal
puts "awaiting signal"
done.receive
puts "exiting"
When we run this program, it will block waiting for a signal. By typing ctrl-C
(which the terminal shows as ^C
), we can send a SIGINT
signal, causing the program to print SIGINT
and then exit.
$ crystal run signals.cr
awaiting signal
^C
SIGINT
exiting
In Crystal, we use the Signal
module to handle Unix signals. Instead of using a buffered channel like in the original example, we use Crystal’s trap
method to set up signal handlers. These handlers send the received signals to a channel.
We use fibers (Crystal’s lightweight threads) instead of goroutines, but the concept is similar. The main fiber waits for a value on the done
channel, which is sent when a signal is received.
This example demonstrates Crystal’s concurrency model using channels and fibers, as well as its signal handling capabilities.