Title here
Summary here
Here’s the translation of the rate limiting example from Go to Haskell:
import Control.Concurrent (forkIO, threadDelay)
import Control.Concurrent.Chan
import Control.Monad (forM_, replicateM_)
import Data.Time.Clock (UTCTime, getCurrentTime)
main :: IO ()
main = do
-- First we'll look at basic rate limiting. Suppose
-- we want to limit our handling of incoming requests.
-- We'll serve these requests off a channel of the
-- same name.
requests <- newChan
forM_ [1..5] $ \i -> writeChan requests i
-- This limiter channel will receive a value
-- every 200 milliseconds. This is the regulator in
-- our rate limiting scheme.
limiter <- newChan
-- By blocking on a receive from the limiter channel
-- before serving each request, we limit ourselves to
-- 1 request every 200 milliseconds.
forkIO $ forever $ do
threadDelay 200000 -- 200 milliseconds
writeChan limiter ()
replicateM_ 5 $ do
_ <- readChan limiter
req <- readChan requests
time <- getCurrentTime
putStrLn $ "request " ++ show req ++ " " ++ show time
-- We may want to allow short bursts of requests in
-- our rate limiting scheme while preserving the
-- overall rate limit. We can accomplish this by
-- buffering our limiter channel. This burstyLimiter
-- channel will allow bursts of up to 3 events.
burstyLimiter <- newChan
-- Fill up the channel to represent allowed bursting.
replicateM_ 3 $ getCurrentTime >>= writeChan burstyLimiter
-- Every 200 milliseconds we'll try to add a new
-- value to burstyLimiter, up to its limit of 3.
forkIO $ forever $ do
threadDelay 200000 -- 200 milliseconds
getCurrentTime >>= writeChan burstyLimiter
-- Now simulate 5 more incoming requests. The first
-- 3 of these will benefit from the burst capability
-- of burstyLimiter.
burstyRequests <- newChan
forM_ [1..5] $ \i -> writeChan burstyRequests i
replicateM_ 5 $ do
_ <- readChan burstyLimiter
req <- readChan burstyRequests
time <- getCurrentTime
putStrLn $ "request " ++ show req ++ " " ++ show time
This Haskell code implements rate limiting using channels (Chan
) and threads. Here’s a breakdown of the translation:
Control.Concurrent.Chan
for channels instead of Go’s built-in channels.forkIO
for creating new threads.time.Tick
, we use threadDelay
in a loop to simulate ticking.close
function for channels is not needed in Haskell as channels are garbage collected.getCurrentTime
from Data.Time.Clock
to get the current time, similar to Go’s time.Now()
.Running this program will show a similar output to the Go version, with requests being rate-limited and the bursty limiter allowing short bursts of requests.
Note that Haskell’s concurrency model is different from Go’s, and this translation aims to replicate the behavior rather than provide an idiomatic Haskell solution. In practice, you might use more Haskell-specific concurrency primitives for rate limiting.