taoensso / carmine

Redis client + message queue for Clojure
https://www.taoensso.com/carmine
Eclipse Public License 1.0
1.15k stars 130 forks source link

car-mq/enqueue throws Cannot invoke "java.util.concurrent.Future.get()" #255

Closed theronic closed 2 years ago

theronic commented 2 years ago

Running Clojure v1.10.3 and Redis v6.2.2, Carmine throws a NullPointerException when attempting to enqueue a message onto a message queue:

(require '[taoensso.carmine.message-queue :as car-mq])

(car-mq/worker {:pool {} :spec {}}
           "myqueue"
           {:handler (fn [{:keys [message attempt]}]
                       (log/info "Received" message)
                       {:status :success})})
;; workre starts successfully.

(car-mq/enqueue "myqueue" "hi there")
=> Execution error (NullPointerException) at taoensso.carmine.protocol/pull-requests (protocol.clj:288).
Cannot invoke "java.util.concurrent.Future.get()" because "fut" is null
theronic commented 2 years ago

Seems to be caused by @req-queue_ in protocol.clj, which lives in *context*:

(defn- pull-requests "Implementation detail" [req-queue_]
  (loop []
    (let [rq @req-queue_] ;; here
      (if (compare-and-set! req-queue_ rq [])
        rq
        (recur)))))

reqqueue is destructured out of *context*, which ought to be an (atom []), dynamically bound by with-context:

(defmacro with-context "Implementation detail"
  [conn & body]
  `(binding [*context* (->Context ~conn (atom []))
             *parser*  nil]
     ~@body))

Not sure why req-queue_ is not set.

ptaoussanis commented 2 years ago

@theronic Hi Petrus,

enqueue calls need to be made within the context of a Carmine connection, please see the README example.

Hope that helps!

theronic commented 2 years ago

Ah, just figured out need to wrap in (wcar* ...) (other commands warn about this). Thanks, @ptaoussanis :).

ptaoussanis commented 2 years ago

No problem. The motivation for requiring an explicit context is that this choice allows pipelining of message queue commands just like any other Redis commands. This can be useful for performance and convenience / code readability.

In general, you can alway assume that a wcar is necessary for all Carmine Redis commands unless a docstring specifically says otherwise. It's rare (the exception) that a Carmine Redis command will do an automatic wcar since this reduces the flexibility mentioned above.