Message from discussion
does promise.get() allow other requests to run on the same thread while it waits?
Received: by 10.236.126.243 with SMTP id b79mr940504yhi.35.1349701964050;
Mon, 08 Oct 2012 06:12:44 -0700 (PDT)
X-BeenThere: play-framework@googlegroups.com
Received: by 10.236.133.84 with SMTP id p60ls8649325yhi.5.gmail; Mon, 08 Oct
2012 06:12:36 -0700 (PDT)
Received: by 10.236.79.7 with SMTP id h7mr1028180yhe.2.1349701956167;
Mon, 08 Oct 2012 06:12:36 -0700 (PDT)
Date: Mon, 8 Oct 2012 06:12:35 -0700 (PDT)
From: Ryan Means <rme...@nazarene.org>
To: play-framework@googlegroups.com
Message-Id: <0f29bfcf-44f1-428a-9ed3-597b39c28763@googlegroups.com>
In-Reply-To: <c5b2ddde-2ace-4eac-8246-6ab99107017f@googlegroups.com>
References: <fd10a16a-6247-408a-b57c-4a969507dc3a@googlegroups.com>
<CAMkwXW5UsitLFeJxCjEA7N186XoA5CB3Ayz2C3WXTV_CqWAO5g@mail.gmail.com>
<e68aa7f3-21c4-477c-b8ae-9d6d474e2971@googlegroups.com>
<9b0121fb-1c87-4da7-8aac-363e4e710bab@googlegroups.com>
<85a83cb6-669f-4edc-8e87-f14e6f83f944@googlegroups.com>
<5d176998-fb60-4e51-9ee5-047c8b68bd19@googlegroups.com>
<6e2a901d-f2ce-4207-bffa-9c0de9c34611@googlegroups.com>
<f48aae7f-06af-4b01-b60e-21edf958e63f@googlegroups.com>
<2ef77b76-342a-466e-9e9a-ac5beb4e5760@googlegroups.com>
<c5b2ddde-2ace-4eac-8246-6ab99107017f@googlegroups.com>
Subject: Re: [play-framework] does promise.get() allow other requests to run
on the same thread while it waits?
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_Part_103_3230256.1349701955845"
------=_Part_103_3230256.1349701955845
Content-Type: multipart/alternative;
boundary="----=_Part_104_33399224.1349701955845"
------=_Part_104_33399224.1349701955845
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
Thanks for the response James! Even though there are some gray areas right
now when trying to do blocking style apps - we still believe that Play is
the best web development framework out there for Java development shops -
you just need to figure out how to work around things like async and
understand the ramifications (such as what happens to your static content).
Thanks for the good work - I'm excited to see what Play will look like one
year from now..
On Sunday, October 7, 2012 8:11:40 PM UTC-5, James Roper wrote:
>
> No you're right on this. What we probably should do is have a few
> different configuration profiles documented that a user can use. Out of
> the box, Play is tuned for async. We should make it very easy for the user
> to switch to a more traditional model, such as what most servlet containers
> use, where there is one large (150 threads) thread pool that handles all
> requests.
>
> On Saturday, 6 October 2012 05:40:58 UTC+10, Ryan Means wrote:
>>
>> Due to the very reason of what James Roper mentioned in the amount of
>> boiler plate code for Java we're staying completely non-async for now.
>> Ended up following James Ward's blog on how to tune a Play 2 app for
>> non-async (James works for Heroku)
>> http://www.jamesward.com/2012/06/25/optimizing-play-2-for-database-driven-apps.
>> All of our data comes off an in-house rest service from our CRM that is
>> sitting directly on a DB. As much as we would have liked to go async, the
>> Java code was going to be extremely thick as even our webapp text (which we
>> cache in memcached) comes out of our CRM. Over time, we will start
>> migrating our slower methods (methods that don't return within 1 sec) to
>> async.
>>
>> I would like to point out one very glaring issue that James Ward did not
>> mention though - even though you've "tuned" the environment, as James Roper
>> points out ALL requests are handed off to the Akka handler - from our
>> testing - this appears to include static content! So say you have 20
>> threads, and all 20 are blocked at the moment, then 1 thread finishes and
>> sends the result to the browser - the browser loads the HTML and sends
>> requests back to the play server to get the static content referenced in
>> the dynamic html output from play.. well, now your simple static content
>> requests may be blocked waiting on those blocking akka calls to finish
>> before it can return your simple static content! We experienced this in our
>> testing using firebug and gatling. We were noticing that while running a
>> gatling instance against our blocking app, we could load pages (with a wait
>> time) but then noticed that the static resources in firebug were also
>> blocking instead of being immediately returned! To fix this, we ended up
>> going to a front-end apache server so play only deals with dynamic content
>> now. If you went' all async, you wouldn't have to worry about this as Play
>> encourages you to do. Ultimately, it would be nice if Play had a separate
>> akka thread pool for static content so you never would be at risk for this
>> happening.
>>
>> If I'm wrong on any of this - please correct me! :-)
>>
>>
>> On Thursday, October 4, 2012 5:42:47 PM UTC-5, James Roper wrote:
>>>
>>> Hi Ben,
>>>
>>> Sorry, I completely missed this message a month ago.
>>>
>>> There's no strict rules here, multiple solutions will work well, and
>>> it's very dependent on the profile of your app.
>>>
>>> I don't have a video from the talk, there are keynote slides in the
>>> github repository but there's not much in them. I will probably be giving
>>> this talk again in the not too distant future at a conference that does
>>> record video, and it will go into more detail and I'll produce more
>>> comprehensive notes for it, so you'll be able to see it then.
>>>
>>> I think a good start is that anything that relies on third party
>>> services should be asynchronous. There's nothing worse than your app going
>>> down because some other system completely outside of your control is not
>>> responding and tying up all your applications threads while you try to make
>>> calls on it. Calls to internal systems in your company are also good to
>>> make asynchronous, and I would always do that, means my services can't
>>> bring each other down so easily.
>>>
>>> When it comes to talking to databases, for simple lookups that are
>>> entirely from indexes, then I'd say unless you have an asynchronous driver
>>> for that database, then it's probably not necessary to do things
>>> asynchronously. The exception to this is if you need to make many database
>>> calls per request, then doing them in parallel is a good idea. If you've
>>> got big queries, map reduces etc, then this may be good to do
>>> asynchronously too. And if you're doing lots of all of the above, then
>>> take a look at Akka, because with Akka you will have a lot more control
>>> over how many threads are devoted to doing what. Klout did a great blog
>>> post about this:
>>> http://corp.klout.com/blog/2012/10/scaling-the-klout-api-with-scala-akka-and-play/
>>>
>>> The final thing to be said, if you're doing Java, using promises or any
>>> sort of async stuff has a huge boiler plate overhead, and this needs to be
>>> considered, if your simplest code paths are just one anonymous class after
>>> another, then you are making large maintainability/code readability trade
>>> offs, and it might not be worth it. If doing Scala on the other hand,
>>> working with Promises is no harder than working with Options, and so from a
>>> code perspective, as long as you're comfortable with the concepts of map
>>> and flatmap, there's no disadvantage to using promises.
>>>
>>> Cheers,
>>>
>>> James
>>>
>>> On Monday, 3 September 2012 07:43:00 UTC+10, Ben McCann wrote:
>>>>
>>>> Hi James,
>>>>
>>>> Do you happen to have a video or slides from that talk you gave? I
>>>> have a very poor understanding of what should be wrapped in a promise and
>>>> the docs are quite anemic on the topic. E.g. should all of my calls via
>>>> the Mongo Jackson Mapper be wrapped in promises? Or just external HTTP
>>>> requests? How long should an action take before it is recommended to wrap
>>>> it in a promise? Why not just wrap every single request in a promise? I'm
>>>> having a really hard time understanding what tradeoffs are in play here.
>>>>
>>>> Thanks,
>>>> Ben
>>>>
>>>>
>>>> On Thursday, August 30, 2012 11:10:33 PM UTC-7, James Roper wrote:
>>>>>
>>>>> I think you've fundamentally misunderstood how promises work. A
>>>>> promise says "at some point in future, I promise I will make one of these
>>>>> available." In the case of the WS API, that is a WS.Response, ie
>>>>> Promise<WS.Response>. When returning an async response to Play, you want
>>>>> to return a promise for a result, ie Promise<Result>. You can convert a
>>>>> Promise<WS.Response> to a Promise<Result> by calling the map function,
>>>>> which accepts a function that takes a WS.Response and returns a Result.
>>>>> This isn't invoked immediately, it's invoked when the first promise makes
>>>>> the WS.Response available. You could map it to something else first if you
>>>>> really wanted, and then map that thing to a promise, eg:
>>>>>
>>>>> Promise<WS.Response> responsePromise = WS.url(...).get();
>>>>> Promise<Foo> fooPromise = responsePromise.map(new Function<...> {
>>>>> public apply(WS.Response response) { return
>>>>> Json.fromJson(response.asJson(), Foo.class); }};
>>>>> Promise<Result> resultPromise = responsePromise.map(new Function<...>
>>>>> { public apply(Foo foo) { return Result(foo); }};
>>>>> return async(resultPromise);
>>>>>
>>>>> But that's a bit unnecessary, because you don't need the intermediate
>>>>> fooPromise, you could put your code that converts to/from json in the first
>>>>> map function. This is also, if you were to call other libraries, where you
>>>>> would put all that code. If you want to do another async operation (eg two
>>>>> WS calls), then you can use flatmap:
>>>>>
>>>>> Promise<WS.Response> responsePromise = WS.url().get()...
>>>>> Promise<WS.Response> secondResponsePromise =
>>>>> responsePromise.flatMap(new Function<...> { public apply(WS.Response
>>>>> response) { return WS.url(..).get(); }};
>>>>> Promise<Result> resultPromise = secondResponsePromise.map(new
>>>>> Function<...> { public apply(WS.Response response) { return Ok(...); }};
>>>>>
>>>>> The thing to be aware, is once you start working with Promises, you
>>>>> can never directly work with the result, everything gets done in map() and
>>>>> flatMap().
>>>>>
>>>>> There's a keynote presentation and example code here that I did for a
>>>>> Play user group:
>>>>>
>>>>> https://github.com/jroper/play-promise-presentation
>>>>>
>>>>> On Friday, August 31, 2012 7:49:55 AM UTC+2, Steven Wong wrote:
>>>>>>
>>>>>> Ok I think I may have found the solution, posted at SOF
>>>>>>
>>>>>>
>>>>>> http://stackoverflow.com/questions/12201047/play-2-async-webservice-call-without-using-asyncresult/12209575#12209575
>>>>>>
>>>>>> On Friday, August 31, 2012 1:54:42 AM UTC+10, Steven Wong wrote:
>>>>>>>
>>>>>>> I also have the same question. Especially when you have to perform
>>>>>>> more actions on the result from the WS call before returning a result to
>>>>>>> the user?
>>>>>>>
>>>>>>> AsyncResult won't allow you to do that so you're left with blocking
>>>>>>> the server.
>>>>>>>
>>>>>>> On Tuesday, July 10, 2012 6:39:31 AM UTC+10, Aldrion wrote:
>>>>>>>>
>>>>>>>> Hi, my questions pertains to this exact problem Jonathan has
>>>>>>>> introduced, but from a different angle and I haven't been able to find a
>>>>>>>> solution (at least not of the kind that would enlighten me) online. Namely,
>>>>>>>> while it is self-evident, how you get to a JsonNode (or any other data) in
>>>>>>>> the second Jonathan's example, I can't seem to get my head around
>>>>>>>> comprehending, how do you get a JsonNode or any other data out of the
>>>>>>>> async() method through Java libraries? All the examples I have come across
>>>>>>>> only deal with returning a Result with an ok() method.
>>>>>>>>
>>>>>>>> Using F.Promise's get() blocks the thread (or at least so I
>>>>>>>> understand) and as such obviously negates one of the Play!'s fortes, while
>>>>>>>> async() as per my understanding only takes Promise<Result> as an argument
>>>>>>>> and returns AsyncResult exclusively, and neither Result nor AsyncResult
>>>>>>>> seem to offer any usable method. Is there any way to collect/fetch data
>>>>>>>> from Result or AsyncResult that I am not aware of? Or is there an
>>>>>>>> altogether different way of tackling this?
>>>>>>>>
>>>>>>>> Any advise would be greatly appreciated...
>>>>>>>>
>>>>>>>
------=_Part_104_33399224.1349701955845
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Thanks for the response James! Even though there are some gray areas right =
now when trying to do blocking style apps - we still believe that Play is t=
he best web development framework out there for Java development shops - yo=
u just need to figure out how to work around things like async and understa=
nd the ramifications (such as what happens to your static content). Thanks =
for the good work - I'm excited to see what Play will look like one year fr=
om now..<br><br>On Sunday, October 7, 2012 8:11:40 PM UTC-5, James Roper wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">No you're right on this. &=
nbsp;What we probably should do is have a few different configuration profi=
les documented that a user can use. Out of the box, Play is tuned for=
async. We should make it very easy for the user to switch to a more =
traditional model, such as what most servlet containers use, where there is=
one large (150 threads) thread pool that handles all requests.<br><br>On S=
aturday, 6 October 2012 05:40:58 UTC+10, Ryan Means wrote:<blockquote clas=
s=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc =
solid;padding-left:1ex">Due to the very reason of what James Roper mentione=
d in the amount of boiler plate code for Java we're staying completely non-=
async for now. Ended up following James Ward's blog on how to tune a Play 2=
app for non-async (James works for Heroku) <a href=3D"http://www.jamesward=
.com/2012/06/25/optimizing-play-2-for-database-driven-apps" target=3D"_blan=
k">http://www.jamesward.com/2012/<wbr>06/25/optimizing-play-2-for-<wbr>data=
base-driven-apps</a>. All of our data comes off an in-house rest service fr=
om our CRM that is sitting directly on a DB. As much as we would have liked=
to go async, the Java code was going to be extremely thick as even our web=
app text (which we cache in memcached) comes out of our CRM. Over time, we =
will start migrating our slower methods (methods that don't return within 1=
sec) to async. <br><br>I would like to point out one very glaring issue th=
at James Ward did not mention though - even though you've "tuned" the envir=
onment, as James Roper points out ALL requests are handed off to the Akka h=
andler - from our testing - this appears to include static content! So say =
you have 20 threads, and all 20 are blocked at the moment, then 1 thread fi=
nishes and sends the result to the browser - the browser loads the HTML and=
sends requests back to the play server to get the static content reference=
d in the dynamic html output from play.. well, now your simple static conte=
nt requests may be blocked waiting on those blocking akka calls to finish b=
efore it can return your simple static content! We experienced this in our =
testing using firebug and gatling. We were noticing that while running a ga=
tling instance against our blocking app, we could load pages (with a wait t=
ime) but then noticed that the static resources in firebug were also blocki=
ng instead of being immediately returned! To fix this, we ended up going to=
a front-end apache server so play only deals with dynamic content now. If =
you went' all async, you wouldn't have to worry about this as Play encourag=
es you to do. Ultimately, it would be nice if Play had a separate akka thre=
ad pool for static content so you never would be at risk for this happening=
.<br><br>If I'm wrong on any of this - please correct me! :-)<br><br><br>On=
Thursday, October 4, 2012 5:42:47 PM UTC-5, James Roper wrote:<blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex">Hi Ben,<div><br></div><div>Sorry, I completely =
missed this message a month ago.</div><div><br></div><div>There's no strict=
rules here, multiple solutions will work well, and it's very dependent on =
the profile of your app.</div><div><br></div><div>I don't have a video from=
the talk, there are keynote slides in the github repository but there's no=
t much in them. I will probably be giving this talk again in the not =
too distant future at a conference that does record video, and it will go i=
nto more detail and I'll produce more comprehensive notes for it, so you'll=
be able to see it then.</div><div><br></div><div>I think a good start is t=
hat anything that relies on third party services should be asynchronous. &n=
bsp;There's nothing worse than your app going down because some other syste=
m completely outside of your control is not responding and tying up all you=
r applications threads while you try to make calls on it. Calls to in=
ternal systems in your company are also good to make asynchronous, and I wo=
uld always do that, means my services can't bring each other down so easily=
.</div><div><br></div><div>When it comes to talking to databases, for simpl=
e lookups that are entirely from indexes, then I'd say unless you have an a=
synchronous driver for that database, then it's probably not necessary to d=
o things asynchronously. The exception to this is if you need to make=
many database calls per request, then doing them in parallel is a good ide=
a. If you've got big queries, map reduces etc, then this may be good =
to do asynchronously too. And if you're doing lots of all of the abov=
e, then take a look at Akka, because with Akka you will have a lot more con=
trol over how many threads are devoted to doing what. Klout did a gre=
at blog post about this: <a href=3D"http://corp.klout.com/blog/2012/10=
/scaling-the-klout-api-with-scala-akka-and-play/" target=3D"_blank">http://=
corp.klout.com/<wbr>blog/2012/10/scaling-the-<wbr>klout-api-with-scala-akka=
-and-<wbr>play/</a></div><div><br></div><div>The final thing to be said, if=
you're doing Java, using promises or any sort of async stuff has a huge bo=
iler plate overhead, and this needs to be considered, if your simplest code=
paths are just one anonymous class after another, then you are making larg=
e maintainability/code readability trade offs, and it might not be worth it=
. If doing Scala on the other hand, working with Promises is no harde=
r than working with Options, and so from a code perspective, as long as you=
're comfortable with the concepts of map and flatmap, there's no disadvanta=
ge to using promises.</div><div><br></div><div>Cheers,</div><div><br></div>=
<div>James</div><div><br>On Monday, 3 September 2012 07:43:00 UTC+10, Ben M=
cCann wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-lef=
t:0.8ex;border-left:1px #ccc solid;padding-left:1ex">Hi James,<div><br></di=
v><div>Do you happen to have a video or slides from that talk you gave? &nb=
sp;I have a very poor understanding of what should be wrapped in a promise =
and the docs are quite anemic on the topic. E.g. should all of my cal=
ls via the Mongo Jackson Mapper be wrapped in promises? Or just exter=
nal HTTP requests? How long should an action take before it is recomm=
ended to wrap it in a promise? Why not just wrap every single request=
in a promise? I'm having a really hard time understanding what trade=
offs are in play here.</div><div><br></div><div>Thanks,</div><div>Ben</div>=
<div><br><div><br>On Thursday, August 30, 2012 11:10:33 PM UTC-7, James Rop=
er wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex">I think you've fundamental=
ly misunderstood how promises work. A promise says "at some point in =
future, I promise I will make one of these available." In the case of=
the WS API, that is a WS.Response, ie Promise<WS.Response>. Wh=
en returning an async response to Play, you want to return a promise for a =
result, ie Promise<Result>. You can convert a Promise<WS.Res=
ponse> to a Promise<Result> by calling the map function, which acc=
epts a function that takes a WS.Response and returns a Result. This i=
sn't invoked immediately, it's invoked when the first promise makes the WS.=
Response available. You could map it to something else first if you r=
eally wanted, and then map that thing to a promise, eg:<div><br></div><div>=
Promise<WS.Response> responsePromise =3D WS.url(...).get();</div><div=
>Promise<Foo> fooPromise =3D responsePromise.map(new Function<...&=
gt; { public apply(WS.Response response) { return Json.fromJson(response.as=
Json(<wbr>), Foo.class); }};</div><div>Promise<Result> resultPromise =
=3D responsePromise.map(new Function<...> { public apply(Foo foo) { r=
eturn Result(foo); }};</div><div>return async(resultPromise);</div><div><br=
></div><div>But that's a bit unnecessary, because you don't need the interm=
ediate fooPromise, you could put your code that converts to/from json in th=
e first map function. This is also, if you were to call other librari=
es, where you would put all that code. If you want to do another asyn=
c operation (eg two WS calls), then you can use flatmap:</div><div><br></di=
v><div><div>Promise<WS.Response> responsePromise =3D WS.url().get()..=
.</div><div>Promise<WS.Response> secondResponsePromise =3D responsePr=
omise.flatMap(new Function<...> { public apply(WS.Response response) =
{ return WS.url(..).get(); }};</div></div><div><div>Promise<Result> r=
esultPromise =3D secondResponsePromise.map(new Function<...> { public=
apply(WS.Response response) { return Ok(...); }};</div></div><div><br></di=
v><div>The thing to be aware, is once you start working with Promises, you =
can never directly work with the result, everything gets done in map() and =
flatMap().</div><div><br></div><div>There's a keynote presentation and exam=
ple code here that I did for a Play user group:</div><div><br></div><div><a=
href=3D"https://github.com/jroper/play-promise-presentation" target=3D"_bl=
ank">https://github.com/jroper/<wbr>play-promise-presentation</a><br></div>=
<div><br>On Friday, August 31, 2012 7:49:55 AM UTC+2, Steven Wong wrote:<bl=
ockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-l=
eft:1px #ccc solid;padding-left:1ex">Ok I think I may have found the soluti=
on, posted at SOF<br><br><a href=3D"http://stackoverflow.com/questions/1220=
1047/play-2-async-webservice-call-without-using-asyncresult/12209575#122095=
75" target=3D"_blank">http://stackoverflow.com/<wbr>questions/12201047/play=
-2-<wbr>async-webservice-call-without-<wbr>using-asyncresult/12209575#<wbr>=
12209575</a><br><br>On Friday, August 31, 2012 1:54:42 AM UTC+10, Steven Wo=
ng wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex">I also have the same quest=
ion. Especially when you have to perform more actions on the result from th=
e WS call before returning a result to the user?<br><br>AsyncResult won't a=
llow you to do that so you're left with blocking the server.<br><br>On Tues=
day, July 10, 2012 6:39:31 AM UTC+10, Aldrion wrote:<blockquote class=3D"gm=
ail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;p=
adding-left:1ex">Hi, my questions pertains to this exact problem Jonathan h=
as introduced, but from a different angle and I haven't been able to find a=
solution (at least not of the kind that would enlighten me) online. Namely=
, while it is self-evident, how you get to a JsonNode (or any other data) i=
n the second Jonathan's example, I can't seem to get my head around compreh=
ending, how do you get a JsonNode or any other data out of the async() meth=
od through Java libraries? All the examples I have come across only deal wi=
th returning a Result with an ok() method.<br><br>Using F.Promise's get() b=
locks the thread (or at least so I=20
understand) and as such obviously negates one of the Play!'s fortes, while =
async() as per my understanding only takes Promise<Result> as an argu=
ment and returns AsyncResult exclusively, and neither Result nor AsyncResul=
t seem to offer any usable method. Is there any way to collect/fetch data f=
rom Result or AsyncResult that I am not aware of? Or is there an altogether=
different way of tackling this?<br><br>Any advise would be greatly appreci=
ated...<br></blockquote></blockquote></blockquote></div></blockquote></div>=
</div></blockquote></div></blockquote></blockquote></blockquote>
------=_Part_104_33399224.1349701955845--
------=_Part_103_3230256.1349701955845--