I’m using a Clojure application to access data from a web API. I’m going to be making a lot of requests, and many of the requests will lead to more requests being made, so I want to keep the request URLs in a queue that will leave 60 seconds between subsequent downloads.
Following this blog post I put this together:
(def queue-delay (* 1000 60)) ; one minute
(defn offer!
[q x]
(.offerLast q x)
q)
(defn take!
[q]
(.takeFirst q))
(def my-queue (java.util.concurrent.LinkedBlockingDeque.))
(defn- process-queue-item
[item]
(println ">> " item) ; this would be replaced by downloading `item`
(Thread/sleep queue-delay))
If I include a (future (process-queue-item (take! my-queue))) in my code somewhere then at the REPL I can (offer! my-queue "something") and I see the “>> something” printed immediately. So far so good! But I need the queue to last for the entire time my program is active. The (future ...) call I just mentioned works to pull one item out of the queue, once it’s available, but I want something that will watch the queue continually and call process-queue-item whenever something is available.
Also, contrary to the usual Clojure love for concurrency, I want to ensure that only one request is being made at a time and that my program waits 60 seconds to make each subsequent request.
I think this Stack Overflow question is relevant, but I’m not sure how to adapt it to do what I want. How do I poll my queue continuously and ensure that only one request is being run at once?
I ended up rolling my own small library, which I called simple-queue. You can read the full documentation on GitHub, but here is the source in its entirety. I’m not going to keep this answer updated, so if you’d like to use this library please get the source from GitHub.
An example of using this queue to return values:
The calls to
q/processwill block so that there will be a 30-second delay between the twodefstatements.An example of using this queue purely for side effects:
Now the calls to
q/addreturn immediately.