                      :eoq-backoff-ms eoq-backoff-ms
                      :throttle-ms    throttle-ms})]
     (when auto-start? (start w)) w))
-
-(comment
-  (def w1 (worker {} "myq"))
-  (wcar {} (enqueue "myq" "msg"))
-  (stop w1)
-  (queue-status {} "myq"))
 
 ;;;; Renamed/deprecated
 

    \"eoq-backoff\" - If circle uninitialized or end-of-circle marker reached.
    [<mid> <mcontent> <attempt-count>] - If message should be (re)handled now."
  [qname & [{:keys [lock-ms eoq-backoff-ms]
             :or   {lock-ms (* 1000 60 60)
                    eoq-backoff-ms 2000}}]]
  (car/lua
   "if redis.call('exists', _:qk-eoq-backoff) == 1 then return 'eoq-backoff' end

    -- TODO Waiting for Lua brpoplpush support to get us long polling
    local mid = redis.call('rpoplpush', _:qk-mid-circle, _:qk-mid-circle)
    local now = tonumber(_:now)

    if (not mid) or (mid == 'end-of-circle') then
      -- Set queue-wide polling backoff flag
      redis.call('psetex', _:qk-eoq-backoff, _:eoq-backoff-ms, 'true')
      redis.call('incr',   _:qk-ndry-runs)

      -- Prune expired backoffs. We have to do this manually if we want to keep
      -- backoffs in a hash as we do for efficiency & Cluster support. This hash
      -- is usu. quite small since it consists only of active retry and dedupe
      -- backoffs.
      for i,k in pairs(redis.call('hkeys', _:qk-backoffs)) do
        if (now >= tonumber(redis.call('hget', _:qk-backoffs, k))) then
          redis.call('hdel', _:qk-backoffs, k)
        end
      end

      return 'eoq-backoff'
    end

    if redis.call('sismember', _:qk-gc, mid) == 1 then -- GC
      redis.call('lrem', _:qk-mid-circle, 1, mid) -- Efficient here
      redis.call('srem', _:qk-gc,            mid)
      redis.call('hdel', _:qk-msgs,          mid)
      redis.call('hdel', _:qk-locks,         mid)
      --redis.call('hdel', _:qk-backoffs,    mid) -- No! Will use as dedupe backoff
      redis.call('hdel', _:qk-nattempts,     mid)
      redis.call('set',  _:qk-ndry-runs, 0) -- Did work
      return nil
    end

    local lock_exp    = tonumber(redis.call('hget', _:qk-locks,    mid) or 0)
    local backoff_exp = tonumber(redis.call('hget', _:qk-backoffs, mid) or 0)

    -- Active lock/backoff
    if (now < lock_exp) or (now < backoff_exp) then return nil end

    redis.call('hset', _:qk-locks,    mid, now + tonumber(_:lock-ms)) -- Acquire
    redis.call('hdel', _:qk-backoffs, mid) -- Expired, so prune (keep gc-prune fast)
    redis.call('set',  _:qk-ndry-runs, 0) -- Did work

    local mcontent  = redis.call('hget',    _:qk-msgs,      mid)
    local nattempts = redis.call('hincrby', _:qk-nattempts, mid, 1)
    return {mid, mcontent, nattempts}"
   {:qk-msgs        (qkey qname :msgs)
    :qk-locks       (qkey qname :locks)
    :qk-backoffs    (qkey qname :backoffs)
    :qk-nattempts   (qkey qname :nattempts)
    :qk-mid-circle  (qkey qname :mid-circle)
    :qk-gc          (qkey qname :gc)
    :qk-eoq-backoff (qkey qname :eoq-backoff?)
    :qk-ndry-runs   (qkey qname :ndry-runs)}
   {:now            (System/currentTimeMillis)
    :lock-ms        lock-ms
    :eoq-backoff-ms eoq-backoff-ms}))

(comment
  (clear-queues {} "myq")
  (queue-status {} "myq")
  (let [mid (wcar {} (enqueue "myq" "msg"))]
    (wcar {} (message-status "myq" mid)))

  (wcar {} (dequeue "myq")))

(defn handle1 "Implementation detail!"
  [conn qname handler [mid mcontent attempt :as poll-reply]]

;;;; Public utils

(defn exp-backoff "Returns binary exponential backoff value."
  [attempt & [{:keys [factor min max] :or {factor 2200}}]]
  (let [binary-exp (Math/pow 2 (dec attempt))
        time (* (+ binary-exp (rand binary-exp)) 0.5 factor)]
    (long (let [time (if min (clojure.core/max min time) time)
                time (if max (clojure.core/min max time) time)]
            time))))

(comment (mapv #(exp-backoff % {}) (range 5)))

;;;; Admin

