Async handling in 0.3.0

159 views
Skip to first unread message

Henrik L.

unread,
Jul 18, 2014, 8:40:24 AM7/18/14
to pedesta...@googlegroups.com
Hi

I figured out a way to send the response body asynchronously. Here is an example using ruiyun/tools.timer to send the body after two seconds:

(def timer (t/timer))

(defn takes-time [request]
  (let [c (async/chan 1)]
    (t/run-task! (fn []
                   (async/>!! c "Replying after 2 seconds.\n")
                   (async/close! c))
                 :delay 2000 :by timer)
    (-> (ring-resp/response c)
        (ring-resp/content-type "text/plain"))))

But how can I send the whole response asynchronously? I want to decide the HTTP status code and possibly other headers at the same time as sending the body. Is that possible?

It seems like the documentation has fallen quite a bit behind with the 0.3.0 release?


BR

Ryan Neufeld

unread,
Jul 18, 2014, 9:22:54 AM7/18/14
to Henrik L., pedesta...@googlegroups.com
The mix of core.async and non-core.async code seems a little complicated here. Why not use just core.async:

(defn takes-time [request]
  (let [c (async/chan 1)]
    (async/go
      (<! (async/timeout 2000))
      (>! c {:status 200, :body “Hello, World”, :headers {}}))
     c))

The above code *should* return the whole context asynchronously, after 2 seconds of timeout. (A note, you should always use core.async’s timeout channels over Thread/sleep and alternatives, the other methods don’t jive as well with core.async’s implementation.)

Indeed docs have fallen a bit out of date. We made the decision to ship sooner, rather than holding up the release for our admittedly slow documentation-writing process. Feel free to ask any questions on the list/repo as they come up.

-Ryan
--
You received this message because you are subscribed to the Google Groups "pedestal-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pedestal-user...@googlegroups.com.
Visit this group at http://groups.google.com/group/pedestal-users.

signature.asc

Henrik Lundahl

unread,
Jul 18, 2014, 10:10:56 AM7/18/14
to Ryan Neufeld, pedesta...@googlegroups.com
Thanks for the quick reply. That code does indeed look simpler, at least if you have some grasp of core.async.  ;-)

Unfortunately I can't get returning the channel to work, because I get this:

java.lang.ClassCastException: clojure.core.async.impl.channels.ManyToManyChannel cannot be cast to clojure.lang.Associative
at clojure.lang.RT.assoc(RT.java:702) ~[clojure-1.6.0.jar:na]
at clojure.core$assoc.invoke(core.clj:187) ~[clojure-1.6.0.jar:na]
at clojure.core$assoc_in.invoke(core.clj:5685) ~[clojure-1.6.0.jar:na]
at clojure.core$assoc_in.invoke(core.clj:5684) ~[clojure-1.6.0.jar:na]
at io.pedestal.http.secure_headers$secure_headers$fn__8516.invoke(secure_headers.clj:83) ~[na:na]
at clojure.lang.AFn.applyToHelper(AFn.java:154) [clojure-1.6.0.jar:na]
at clojure.lang.AFn.applyTo(AFn.java:144) [clojure-1.6.0.jar:na]
at clojure.core$apply.invoke(core.clj:626) [clojure-1.6.0.jar:na]
at io.pedestal.interceptor$after$fn__6730.invoke(interceptor.clj:134) ~[na:na]
at io.pedestal.impl.interceptor$try_f.invoke(interceptor.clj:39) ~[na:na]
at io.pedestal.impl.interceptor$leave_all_with_binding.invoke(interceptor.clj:166) ~[na:na]
at io.pedestal.impl.interceptor$leave_all$fn__6614.invoke(interceptor.clj:182) [na:na]
at clojure.lang.AFn.applyToHelper(AFn.java:152) [clojure-1.6.0.jar:na]
at clojure.lang.AFn.applyTo(AFn.java:144) [clojure-1.6.0.jar:na]
at clojure.core$apply.invoke(core.clj:624) [clojure-1.6.0.jar:na]
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1862) [clojure-1.6.0.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:425) [clojure-1.6.0.jar:na]
at io.pedestal.impl.interceptor$leave_all.invoke(interceptor.clj:180) [na:na]
at io.pedestal.impl.interceptor$execute.invoke(interceptor.clj:270) [na:na]
...

Seems to me like io.pedestal.http.secure-headers/secure-headers is perhaps running at the wrong time?


--
Henrik

Ryan Neufeld

unread,
Jul 19, 2014, 10:01:50 PM7/19/14
to Henrik Lundahl, pedesta...@googlegroups.com
I’m not sure what is going on here, but I created a pull-request with code to reproduce. https://github.com/pedestal/pedestal/pull/268

-Ryan
signature.asc

Ryan Neufeld

unread,
Jul 21, 2014, 10:02:23 AM7/21/14
to pedesta...@googlegroups.com
OK, so we wrapped up the conversation on the reproduction issue on GitHub:

Here is the finals verdict:
You can't do what you're trying to do. Only an interceptor can make the decision to go async, never a response handler (see the test example linked earlier for proper use).
It is advised that you write an interceptor specific for your async behavior and use that. The interceptor approach is very flexible and would allow you to achieve whatever async situation you're trying to achieve.

Find the rest of the discussion here:. https://github.com/pedestal/pedestal/pull/268

-Ryan
Reply all
Reply to author
Forward
0 new messages