weavejester / compojure

A concise routing library for Ring/Clojure
Eclipse Public License 1.0
4.08k stars 259 forks source link

Routes returning asynchronous ring handlers #171

Closed sachinpkale closed 7 years ago

sachinpkale commented 7 years ago

We use Ring + Compojure heavily in one of our web services. As we are upgrading ring to 1.6.0, wanted to try out async feature. As Compojure routes return ring handlers, I am not able to figure out a way to define routes which will return async ring handlers.

sachinpkale commented 7 years ago

Never mind. I was on older version.

jdormit commented 6 years ago

@sachinpkale did you figure out how to return an async Ring handler from a route? How do you do it?

weavejester commented 6 years ago

@jdormit You literally just return an async handler from the route:

(GET "/async" []
  (fn [_ respond raise] ...))
jdormit commented 6 years ago

Gotcha. Very straightforward 👍

jdormit commented 6 years ago

Hmm, even on 1.6.0 this isn't working for me. I'm getting an arity exception.

My handler and routes look something like:

(defn handler [request respond raise]
  (let [{:keys [foo bar]} (:params request)]
    (go (respond (<! (some-async-function foo bar))))))

(defroutes app-routes
  (GET "/:foo" [foo bar] handler))

(def app
  (wrap-defaults app-routes site-defaults))

Which yields:

clojure.lang.ArityException: Wrong number of args (1) passed to: handler/handler
...
weavejester commented 6 years ago

It sounds like you haven't turned on asynchronous handlers in the adapter.

jdormit commented 6 years ago

Is there a way to do that using ring-server? I tried (serve app {:async? true}) but that did not work.

weavejester commented 6 years ago

That should be fine. Are you using the latest version of Ring, or are your dependencies pulling in an older version? i.e. what does lein deps :tree tell you?

juniorgarcia commented 4 years ago

I'm having the same problem here. Here's the output of lein deps :tree for me.

[clj-http "3.10.0"]
   [commons-codec "1.12" :exclusions [[org.clojure/clojure]]]
   [commons-io "2.6" :exclusions [[org.clojure/clojure]]]
   [org.apache.httpcomponents/httpasyncclient "4.1.4" :exclusions [[org.clojure/clojure]]]
     [org.apache.httpcomponents/httpcore-nio "4.4.10"]
   [org.apache.httpcomponents/httpclient-cache "4.5.8" :exclusions [[org.clojure/clojure]]]
   [org.apache.httpcomponents/httpclient "4.5.8" :exclusions [[org.clojure/clojure]]]
     [commons-logging "1.2"]
   [org.apache.httpcomponents/httpcore "4.4.11" :exclusions [[org.clojure/clojure]]]
   [org.apache.httpcomponents/httpmime "4.5.8" :exclusions [[org.clojure/clojure]]]
   [potemkin "0.4.5" :exclusions [[org.clojure/clojure]]]
     [clj-tuple "0.2.2"]
     [riddley "0.1.12"]
   [slingshot "0.12.2" :exclusions [[org.clojure/clojure]]]
 [clojure-complete "0.2.5" :exclusions [[org.clojure/clojure]]]
 [compojure "1.6.1"]
   [clout "2.2.1"]
     [instaparse "1.4.8" :exclusions [[org.clojure/clojure]]]
   [medley "1.0.0"]
   [org.clojure/tools.macro "0.1.5"]
   [ring/ring-codec "1.1.0"]
   [ring/ring-core "1.6.3"]
     [clj-time "0.11.0"]
       [joda-time "2.8.2"]
     [commons-fileupload "1.3.3"]
     [crypto-equality "1.0.0"]
     [crypto-random "1.2.0"]
 [javax.servlet/servlet-api "2.5" :scope "test"]
 [nrepl "0.6.0" :exclusions [[org.clojure/clojure]]]
 [org.clojure/clojure "1.10.0"]
   [org.clojure/core.specs.alpha "0.2.44"]
   [org.clojure/spec.alpha "0.2.176"]
 [org.clojure/core.async "1.0.567"]
   [org.clojure/tools.analyzer.jvm "0.7.3"]
     [org.clojure/core.memoize "0.8.2"]
       [org.clojure/core.cache "0.8.2"]
         [org.clojure/data.priority-map "0.0.7"]
     [org.clojure/tools.analyzer "0.7.0"]
     [org.clojure/tools.reader "1.3.2"]
     [org.ow2.asm/asm "5.2"]
 [org.clojure/data.json "1.0.0"]
 [ring/ring-defaults "0.3.2"]
   [javax.servlet/javax.servlet-api "3.1.0"]
   [ring/ring-anti-forgery "1.3.0"]
     [hiccup "1.0.5"]
   [ring/ring-headers "0.3.0"]
   [ring/ring-ssl "0.3.0"]
 [ring/ring-mock "0.3.2" :scope "test"]
   [cheshire "5.8.0" :scope "test"]
     [com.fasterxml.jackson.core/jackson-core "2.9.0" :scope "test"]
     [com.fasterxml.jackson.dataformat/jackson-dataformat-cbor "2.9.0" :scope "test"]
     [com.fasterxml.jackson.dataformat/jackson-dataformat-smile "2.9.0" :scope "test"]
     [tigris "0.1.1" :scope "test"]

My main handler file is like this:

(ns async-ring-fetch.handler
  (:require [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))

(defn posts [_ respond]
  (respond "Hello world!"))

(defroutes app-routes
  (GET "/" [] posts))

(def app
  (wrap-defaults app-routes site-defaults))

I'm using:

weavejester commented 4 years ago

@juniorgarcia How are you running app? Have you tried adding an explicit ring/ring-jetty-adapter dependency?

juniorgarcia commented 4 years ago

@weavejester I'm running using lein ring server-headless or lein ring server-headless. I just added [ring/ring-jetty-adapter "1.8.0"] to my project.clj (I'm using Leiningen), and still have the same problem.

Edit: I just followed the basic tutorial installing ring-clojure and it worked, but to start Jetty I had to tell it to be async:

; On the repl
(run-jetty handler {:port  3000 :join? false :async? true })

Do I have to, somehow, tell that to Compojure? My project was created simply with lein new compojure <my-app>

weavejester commented 4 years ago

@juniorgarcia Have you added :ring {:async? true} to your project file?

juniorgarcia commented 4 years ago

@weavejester Oh, not really. Now everything is working as expected. Thank you!