Cool a funcool channel! 😁
\o/
o/
\o
Can I only return a manifold deferred as body in a response but not as a return value?
So I can do this https://funcool.github.io/catacumba/latest/#body-as-deferred-manifold
but not:
(d/chain (jira-api/get-user-groups host user-key)
#(http/ok %))
(defn my-async-handler
[context]
(let [result (d/future (Thread/sleep 1000) "hello world")]
(d/chain result
#(http/ok & {"content-type" "text/plain"}))))
the second one is more obvious
I have a handler in my chain that checks some authorization and does a call with aleph and I would like that to be async
Hmm
Maybe some extend-protocol is missing for the manifold deferred
Yeah I checked the code that seems to be the issue
because catacumba says
2015-08-18 16:11:58,966 WARN [r.s.i.NettyHandlerAdapter] No response sent for GET request to /api/1.0/companies (last handler: catacumba.impl.handlers$eval17761$fn$reify__17763)
Because the return value is handled by one protocol and the body sending by other
Efectivelly....
the deferred imlementation is not found for IHandlerResponse protocol.
Yeah, I'll take a stab at it
Would you like a pull request for that?
Yes and No xD
Seems that the implementation of deffered for body handling not will work as you expect
Oh
This is because the body handling is just the content
but in your examples the deferred will be resolved in a response
not the body content
And I think that your use case is pretty common so this should be solved
True, I want to delegate or return a forbidden
Give me some time for finish that I'm currently working on, and later I will try to fix this inconsistences
Thanks @niwinz much appreciated
Were deploying our app next week with catacumba!
Oh great! Let me know anything
Sure will keep you posted, we are building an atlassian connect addon with it. It is in it's very early stage http://addons.avisi.com/relationsforjira/
Having a lot of fun with catacumba it's pedestal with docs
I'm very glad to hear about this!
One thing... the way to attach a watcher
to deferred is using the (d/on-realized...)
, no?
yes I think so let me double check it for you
(d/on-realized d
(fn [x] (println "success!" x))
(fn [x] (println "error!" x)))
Ok, nice! I will modify almost all implementation of IResponseHandler for async value for make it consistent
async values returned as is, should return a proper response
and async value in body should return the body value
Yeah nice
Then you can basically make a non blocking chain of handlers ^^
Yes!
I have it almost done
I will publish the snapshot release
The 0.6.0-SNAPSHOT is published with that inconsistences fixed and with more tests for that use cases
Please check if it works for you.
Yes thnx @niwinz
Ill trying it out as we speak
restarting the repl....
Ouch
`
ratpack.exec.UnmanagedThreadException: Operation attempted on non Ratpack managed thread 'aleph-pool-1-2'
very strange...
this can happens when you are writting directly to the ratpack from some other thread
Aha I do a call with aleph to a webservice and then process the result
so I should put this in another or a new deferred
or a promise or whatever
hmm no, it just ok, it should work
https://github.com/funcool/catacumba/blob/master/test/catacumba/core_tests.clj#L133
let see this test case. It just execute something in an other thread..
The exception is not related to the response handling
i think
Hmm very weird
I'm trying understand it...
at ratpack.exec.internal.ThreadBinding$$Lambda$99/1786206212.get(Unknown Source)
Can you give me handler code? a little simplfied previw of it...
I want understand why it is happens
Hmm I'll see if I can create a very small example
(defn example
[context]
(d/chain
(http/get "<http://www.google.nl>")
:body
#(cthttp/ok % {:Content-Type "plain/text"})))
[manifold.deferred :as d]
[aleph.http :as http]
[catacumba.http :as cthttp]
Also gives
ratpack.exec.UnmanagedThreadException
yess threadlocals the root of all evil
I know, but ratpack tries to use them for control from that threads the response is written
I'll try to reproduce the error with your code
and try to fix it..
I could also
If it's only a aleph error I could also switch to another http lib
But aleph is the only async lib I know of
I don't want condition your code because catacumba does not handles well this situation.
It is just work in test cases
I'm clearly don't understand xD
Yeah me neither
If I think of something I'll let you know
Your example as is is just works in tests
Really?
Yes...
Ow lol forgot todo (reset) ...
😱
I suspect that in some previous steps to that handler something goes out of the ratpack managed threads
what?
I call this function:
(defn get-user-groups
[host user-key]
(-> (get host "/rest/api/2/user" {:query-params {:key user-key
:expand "groups"}})
(d/chain (fn [{:keys [body]}]
(let [groups (-> body
bs/to-string
(json/decode true)
:groups
:items)]
(mapv :name groups))))
(d/catch (fn [e]
(log/error e "Error occured while retrieving user" user-key)
[]))))
and then do a chain in the handler on this result
The exception happens before
so something along the lines of:
`
(d/chain (get-user-groups ...) (if (foo) (forbidden) (delegate)))
the exception now happens before your code as I can observe in the stack trace
https://github.com/funcool/catacumba/blob/master/src/clojure/catacumba/impl/handlers.clj#L233
As you can observe this is a problematic line and is executed before the handler code
it is nothing related to the handler code instead to something that runs after
how you start the
server or do you have any other chain that wraps something in aleph context...
?
(let [conn (database/context->connection context)
host (:host context)
permitted-groups (set (mapv :permissions/group-name
(database/get-permissions conn host)))
user-key (:userKey (:user context))
user-groups (jira-api/get-user-groups host user-key)]
(d/chain user-groups
set
(fn [_] (ct/delegate context)))))
ohh yess
here is the problem
I think
you are calling the delegate,.. from the aleph context
Now, I'll try to reproduce the error knowing that
Aha and then I am int he wrong thread
That makes alot of sense
Yes, now I can reproduce it...
But I'm currently don't know how I call the delegate in the proper way
it need some research
I have an idea on how to fix it bu at this time I shoud go out 😞
I'll fix it later (in some hours 1 or 2)
As a temporal workaround, use blocking operation and then call the delegate
and when this issue is fixed
you can return to the fully asynchronous way
@niwinz: That's what I am currently doing already :simple_smile:
Thanks for all your help dude
@mitchelkuijpers: I just uploaded an other version to clojars (under 0.6.0-SNAPSHOT) that should allow the fully async delegation process
the only restriction is that the return value of (ct/delegate ctx) should be the response (synchronous or asynchronous) of the handler.
As I can see on your last code pasted here in channel, this is just how you are using. You are just return a deferred with the value of the execution of (ct/delegate...) so this code now should works as expected in fully asynchonous way.
The curren implementation removes some speed improvements introduced previously but is just for fix this issue. I think that for the next version I will have time for fix it definitivelly with proper optimizations.
You Rock @niwinz will try it out tomorrow. Will also check out your code which fixes this, I am curious how you did it 👍
\o/ Let me know any result! Now I go to sleep
Take care that (ct/delegate...) function call signature is changed. It's no longer accepts context as first parameter. Now the ct/delegate is just a special response instead of special case.
Read the changelog for an other, maybe more detailed explanation.
I will update the doc for the next version about this breaking change.
This change simplifies a lot how the context delegation works, because now is just an other response (that can be returned in sync or asynchronous way)
And now. Definitively I go to sleep!
\o/