Tickers in Crystal
Tickers are for when you want to do something repeatedly at regular intervals. Here’s an example of a ticker that ticks periodically until we stop it.
require "time"
ticker = Time::Span.new(0, 0, 0, 500)
done = Channel(Bool).new
spawn do
loop do
select
when done.receive
break
when timeout(ticker)
puts "Tick at #{Time.local}"
end
end
end
# Tickers can be stopped. Once a ticker is stopped it won't receive any more values.
# We'll stop ours after 1600ms.
sleep 1.6.seconds
done.send(true)
puts "Ticker stopped"
In this Crystal program, we’re using a combination of spawn
, loop
, select
, and timeout
to simulate a ticker. The ticker
is defined as a Time::Span
of 500 milliseconds.
We create a Channel
named done
to signal when we want to stop the ticker.
The spawn
block creates a new fiber (Crystal’s lightweight thread) that runs concurrently with the main program. Inside this fiber, we have an infinite loop that uses select
to either receive from the done
channel (which breaks the loop) or timeout after the ticker duration (which simulates a tick).
After creating the ticker, we sleep the main thread for 1.6 seconds, allowing the ticker to tick a few times. Then we send a signal through the done
channel to stop the ticker.
When we run this program, the ticker should tick 3 times before we stop it:
$ crystal run tickers.cr
Tick at 2023-06-07 15:30:00.500
Tick at 2023-06-07 15:30:01.000
Tick at 2023-06-07 15:30:01.500
Ticker stopped
Crystal’s concurrency model is based on fibers and channels, which is similar to Go’s goroutines and channels. However, Crystal uses spawn
to create fibers instead of the go
keyword, and it doesn’t have a built-in ticker type. We’ve simulated the ticker behavior using select
and timeout
.