Thank you very much Jason, it helps me a lot.
One last remark regarding "you can save yourself a worker thread and reuse
the thread they generate the callback from. At that callback point you can
write your response out to the exchange."
When I try to do this, calling x.getResponseSender().send(str) un the
onSuccess callback of the database future, I got an exception
java.lang.IllegalStateException:
UT000004: getResponseChannel() has already been called.
I imagine that the response has already been somehow cleaned up / modified
/ terminated by Undertow when the handler exited (I use
SessionAttachHandler, date() and routing() in my test).
I could not find a way to tell Undertow that I would handle the exchange
and end it manually.
I am using undertow 1.1.1-final maybe this has been fixed since this
version?
Thanks again
Laurent
On Sat Dec 13 2014 at 4:57:33 AM Jason Greene <jason.greene(a)redhat.com>
wrote:
Hello Laurent,
Your hunch is correct. You never want to block the I/O thread as each
thread is shared between many connections, and a pause prevents them from
being processed. It’s totally reasonable to call dispatch(), which
transfers the exchange to the worker pool where you can wait on a database
reply, and in fact this is a normal pattern. The worker pool is sized to be
pretty large as its expected to host lots of waiters. You can of course
tweak this, or dispatch to your own special pool if you like. The big
advantage to an async database call, even with requiring a worker thread,
is that you can do other work while its running if your pattern fits (e.g.
parallel db calls, iterative computation, etc).
Alternatively, if the database provides a callback on complete option, you
can save yourself a worker thread and reuse the thread they generate the
callback from. At that callback point you can write your response out to
the exchange. Just note, that the thread policy of an exchange is that
only one thread at a time can interact with it. If you have a use case
where the a request bounces back and forth (e.g. a very long stream
containing multiple records that must be written to the database as they
com in), then you will need to coordinate locking around that. Such
use-cases though should be weighed against the simplicity of just blocking
in a worker thread.
To answer a second question you have in a comment from your example,
startBlocking() just enables the use of a plain inputstream/outputstream,
which can only be done once you have dispatched and blocking i/o is now ok.
Hope this helps,
-Jason
> On Dec 12, 2014, at 3:44 PM, Laurent Bedubourg <laurent(a)labe.me> wrote:
>
> Ok, I think my mail could be reduced to :
>
> Is it possible possible to transfer the HttpServerExchange
responsibility to another thread ?
>
> Regards
> Laurent
>
>
> On Fri Dec 12 2014 at 7:11:01 PM Laurent Bedubourg <laurent(a)labe.me>
wrote:
> Hello,
>
> I am evaluating Undertow and trying to fit an async database (with
scala, Activate and
https://github.com/mauricio/postgresql-async which
use netty and nio).
>
> The good news is that it more or less works.
>
> My main concern is that the database system create threads using scala
futures and that I am forced to "Await" for the result of my Futures to
send the result to the HttpServerExchange.
>
> I am forced to dispath() the request because Await locks the current
thread and I shouldn't lock the IO thread from my Handler, should I?
>
> It made me wondering : is is really a good idea to use futures + Await
with undertow and more generaly nio?
>
> If the thread pool is limited and I lock threads, even if the database
driver is async and uses nio, am I bitting my own leg?
>
> Thanks for any input you can give me and sorry if it's too scala related
:)
>
> Regards
> Laurent
>
> PS: Here's the handleRequest I am using to test this, any comment or
help welcome too since I am discovering the API.
>
> def handleRequest(x:io.undertow.server.HttpServerExchange){
> if (x.isInIoThread()){
> x.dispatch(this)
> return
> }
> // useful or not? no change
> // x.startBlocking()
>
> // Ok, we are in worker thread we can work a little with database
> // val f = asyncTransactionalChain { implicit context =>
> // for (
> // a <- asyncTransactional { new AMember("aaa") };
> // b <- asyncById[AMember](a.id)
> // ) yield b
> // }
>
> // Simulate database work with just a future
> val f = future {
> Some(1)
> }(scala.concurrent.ExecutionContext.Implicits.global)
>
> // send string to xchange
> def sendReply(str:String){
> x.getResponseHeaders().put(io.undertow.util.Headers.CONTENT_TYPE,
"text/plain")
> x.getResponseSender().send(str)
> // x.endExchange()
> }
>
> // // this fails
> // f.onSuccess {
> // case Some(result) => sendReply(result.toString)
> // }(scala.concurrent.ExecutionContext.Implicits.global)
>
> // // this works
> val result = Await.result(f, Duration(1000, MILLISECONDS))
> sendReply(result.toString)
> }
>
> _______________________________________________
> undertow-dev mailing list
> undertow-dev(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/undertow-dev
--
Jason T. Greene
WildFly Lead / JBoss EAP Platform Architect
JBoss, a division of Red Hat
_______________________________________________
undertow-dev mailing list
undertow-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/undertow-dev