metosin / pohjavirta

Fast & Non-blocking Clojure wrapper for Undertow
169 stars 8 forks source link

Support request body #13

Open plexus opened 4 years ago

plexus commented 4 years ago

When doing a POST request the :body in the request map is nil.

  :body (if (.isBlocking exchange) (.getInputStream exchange))
ikitommi commented 4 years ago

Currently, there is no way to lift all threads to worker pool from XNIO pool. Immutant has :dispatch? option for this. We could have just :dispatch. Without first changing the thread pool, the .isBlocking returns false and :body would just be nil with that code.

kalekale commented 4 years ago

Something like this? https://github.com/metosin/pohjavirta/pull/16

ikitommi commented 4 years ago

PR looks good, one post comment (rebased already) + we are not setting the body yet. Maybe do it only when :dispatch is set? For apps running in XNIO pool, still need to figure out a performant way to stream the body in.

kalekale commented 4 years ago

We are actually setting the body when we are in a blocking thread (:body (if (.isBlocking exchange) (.getInputStream exchange))). Or maybe I misunderstood you. Do you have ideas on how to handle the body in a non-blocking thread? There is receiveFullBytes(cb) and receivePartialBytes(cb) for getting the body asynchronously.

ikitommi commented 4 years ago

Simple way would be to invoke the actual ring/routing handler in the callback only after the body has been read in Full - the bytes could be wrapped into ByteArrayInputStream to be Ring-compatible.

There are many ways to optimize that afterwards: if the data is huge, should be handled in chuncks (I guess the Partial thing), if the route doesn't need the body, there is no idea trying to read it etc. Could be a protocol, that for example reitit-pohjavirta implements by peeking at the [:parameters :body] definition etc.

kalekale commented 4 years ago

"invoke the actual ring/routing handler in the callback" but wouldn't this block the IO thread?

ikitommi commented 4 years ago

It your code is non-blocking, you can run it in the IO Thread. I think there are 4 different ways in this:

1) go fully non-blocking: read the body as non-blocking, handle the request in same pool 2) read the body as non-blocking in XNIO pool, lift the actual request handling to worker pool 3) go blocking, e.g. dispatch the thread to worker, read via stream

kanwei commented 4 years ago

Any update on how to best implement this? I think this is the last issue that needs to be resolved before the library can be used in production. Would be happy to help if the right approach were documented.

bsless commented 3 years ago

Hey everyone, any update? It's been a year