-
Notifications
You must be signed in to change notification settings - Fork 258
Open
Description
We have a large ring/compojure application with lots of api routes. We are trying to use ring's async handlers but we eventually run out of stack if a matching path is not found in time.
(let [handler (apply compojure/routes
(repeat 3000 (compojure/GET "/foo" [] {:status 200 :body "bar"})))]
(handler {:uri "/foo2" :request-method :get}
println
println))
=> java.lang.StackOverflowError: This is fine because it matches a route soon enough
(let [handler (apply compojure/routes
(repeat 3000 (compojure/GET "/foo" [] {:status 200 :body "bar"})))]
(handler {:uri "/foo" :request-method :get}
println
println))
=> {:status 200, :headers {}, :body bar}
=> nilThe issue is that it will create a new entry in the stack for each handler that doesn't match:
(defn routes
"Create a Ring handler by combining several handlers into one."
[& handlers]
(fn
([request]
(apply routing request handlers))
([request respond raise]
(letfn [(f [handlers]
(if (seq handlers)
(let [handler (first handlers)
respond' #(if % (respond %) (f (rest handlers)))]
(handler request respond' raise))
(respond nil)))]
(f handlers)))))Even if you break it into chunks like so, you still get the same error.
(let [handler (apply compojure/routes
(map (fn [_] (apply compojure/routes (repeat 30 (compojure/GET "/foo" [] {:status 200 :body "bar"}))))
(range 100)))]
(handler {:uri "/bar" :request-method :get}
println
println))
=> java.lang.StackOverflowError: This can be rewritten using something like a go loop, but it's possible code is blocking and may unknowingly block peoples core async threads.
Any suggestions?
stardiviner
Metadata
Metadata
Assignees
Labels
No labels