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
exitingIn 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.