Search code examples
clojurereitit

"Unsupported Context on :enter " when reitit interceptors are updated to async


I'm working on reitit http application which uses interceptors.

Below is my code

(ns ic.reitit-interceptor-multithreading)

(require '[reitit.ring :as ring])
(require '[reitit.http :as http])
(require '[reitit.interceptor.sieppari :as sieppari])
(require '[clojure.core.async :refer [go]])
(defn interceptor [number]
  {:enter (fn [ctx]
            (go
              (println "in enter interceptor" number (.getName (Thread/currentThread)))
              (update-in ctx [:request :number] (fnil + 0) number)))})

(def app
  (http/ring-handler
   (http/router
    ["/api"
     {:interceptors [(interceptor 1)]}

     ["/number"
        {:interceptors [(interceptor 10)]
         :get {:interceptors [(interceptor 100)]
               :handler (fn [req]
                          (println "in handler")
                          {:status 200
                           :body (select-keys req [:number])})}}]])

   ;; the default handler
   (ring/create-default-handler)

   ;; executor
   {:executor sieppari/executor}))

When I'm executing the code in repl I get error -

(require '[ic.reitit-interceptor-multithreading :refer :all])
(app {:request-method :get, :uri "/api/number"})

The error I get is -

Loading src/ic/reitit_interceptor_multithreading.clj... done (app {:request-method :get, :uri "/api/number"}) Execution error (ExceptionInfo) at sieppari.core/-invalid-context-type! (core.cljc:34). Unsupported Context on :enter - clojure.core.async.impl.channels.ManyToManyChannel@4abe39b8 in enter interceptor 1 async-dispatch-3

When I remove go macro from interceptor enter function then it is working fine.

How can I fix this issue?


Solution

  • Try to add [sieppari.async.core-async :as ca] into ns definition:

    (ns ic.reitit-interceptor-multithreading
      (:require
        [reitit.ring :as ring]
        [reitit.http :as http]
        [reitit.interceptor.sieppari :as sieppari]
        [clojure.core.async :refer [go]]
        [sieppari.async.core-async :as ca])
      (:gen-class))
    

    Then call (app {:request-method :get, :uri "/api/number"}) again.

    Maybe there is an easier way, so here is full explanation:

    Look into a stack trace and see, which functions are called:

    Interceptor has to return context map (c/context?) or async channel (a/async?). go should return the async channel, so you will look for async? definition. async? is a method of AsyncContext protocol and returns false for any object. sieppari/async/core_async.cljc extends this protocol to async channels, which should return true.