[undertow-dev] scala, activate, nio, async jdbc, future, threads

Laurent Bedubourg laurent at labe.me
Mon Dec 15 01:56:51 EST 2014


Thank you Stuart, I will try this ASAP.

Best regards
Laurent

On Sun, 14 Dec 2014 23:28 Stuart Douglas <sdouglas at redhat.com> wrote:

> You need to call the HttpServerExchange.dispatch() method, which will
> prevent the exchange from being ended once the call stack returns.
>
> There is however a thread safety issue here, as you can have your callback
> being called at the same time as the call stack is still returning, which
> means it is possible to have two threads using the HttpServerExchange,
> which is not thread safe (in practice this will *probably* work fine,
> depending on how your code is written).
>
> The correct way to deal with this is:
>
> HttpServerExchange.dispatch(SameThreadExecutor.INSTANCE, new Runnable() {
>    public void run() {
>       //setup callback
>    }
> }
>
> Basically this does two things, calling dispatch means that the exchange
> will not be ended when the call stack returns, and dispatching using
> SameThreadExecutor means that the runnable will be run immediately after
> the call stack returns in the IO thread (or whatever thread is currently
> active).
>
> If you don't want to use a callback and just want to use await:
>
> HttpServerExchange.dispatch(new Runnable() {
>    public void run() {
>       //call await()
>    }
> }
>
> This will dispatch to the worker thread pool, and await() will be called
> in a worker thread, although if you use this approach you might as well
> just use plain JDBC, as you loose the benefits of non-blocking IO.
>
> Stuart
>
> ------------------------------
>
> *From: *"Laurent Bedubourg" <laurent at labe.me>
> *To: *"Jason Greene" <jason.greene at redhat.com>
> *Cc: *undertow-dev at lists.jboss.org
> *Sent: *Saturday, 13 December, 2014 6:58:51 PM
> *Subject: *Re: [undertow-dev] scala, activate, nio, async jdbc, future,
> threads
>
>
>
> 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 at 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 at 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 at 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 at 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 at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/undertow-dev
>
>
> _______________________________________________
> undertow-dev mailing list
> undertow-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/undertow-dev
>
> _______________________________________________
> undertow-dev mailing list
> undertow-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/undertow-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20141215/e6250e78/attachment.html 


More information about the undertow-dev mailing list