An Elegant Little core.async Solution

Yesterday I had a problem that core.async provides an incredibly neat solution to. Tim Baldridge was kind enough to sanity check it for me, so I thought I'd write it up.

Imagine you want to process a message at a maximum rate of one per second. In another language you'd probably say something like:

while true:
    start_time = date()
    process_message(queue)
    end_time = date()

    elapsed_time = end_time.subtract(start_time)

    if elapsed_time < 1000
        sleep(1000 - elapsed_time)

Not hard to write, of course, but kinda clumsy. Here's the core.async version:

(while true
  (let [t (timeout 1000)]
    (process-message queue)
    (<!! t)))

In English, pick up a ticket that lasts for 1000 milliseconds; process a message; wait until the ticket expires. If processing the message took more than 1000ms, the ticket returns immediately, otherwise it blocks for the remaining time.

Simple and easy. A really neat solution.