tag:robotlegs.tenderapp.com,2009-10-18:/discussions/questions/537-service-promiseasynctoken-handlingRobotlegs: Discussion 2018-10-18T16:35:26Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-12T14:08:26Z2011-05-12T14:08:26ZService - Promise/Asynctoken Handling<div><p>Isn't the point of the AsyncToken that it's handed out
instantly, but won't be populated til later? It's essentially a
"promise" of some results to come.</p>
<p>The caller then binds to the Token, waiting for the results /
errors etc.</p>
<p>Or have I misunderstood something?</p>
<p>The reason for the service creating the AsyncToken is that you
encapsulate the knowledge and responsibility for <em>creating</em>
the AsyncToken in one place - where as if you pass it in then
multiple users have to know how to create (as well as use) the
AsyncToken. If you want to bind to an abstract or interface type
instead of a concrete type then this is important.</p>
<p>But ... I might be missing something in your question.</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-12T14:27:51Z2011-05-12T14:27:51ZService - Promise/Asynctoken Handling<div><p>Yes in theory this totally right and I didn't see any problems
with that so far. The question came to me when I was practically
thinking about client side caching.</p>
<p>When if is this "later" is just a "now"? I just can't do it
without a somehow nasty delay handling inside my service.</p>
<p>But still... I would not create the actual asynctoken outside.
Just a responder Class (mapped to an interface), which then
internally gets linked to a token.</p>
<p>I don't know ... maybe I have to stick to a pattern. But I don't
like if I have to follow something that seems to be limiting
me.</p>
<p>but ... I might missing the point ;)</p>
<p>chris</p></div>egotag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-12T15:58:18Z2011-05-12T15:58:20ZService - Promise/Asynctoken Handling<div><p>Hello,</p>
<p>I think giving back a token like the AsyncToken from Flex could
be quite a dangerous design decision.</p>
<p>First of all you should have the possibility to do some work
between receiving the result and sending it back to the client,
like parsing the result object to a client aware instance or using
some cache mechanism.</p>
<p>Another thing is the clear separation of concern. The "client"
like a command should never get information about infrastructure
details, because it should not be part of the infrastructure layer.
It has completely different responsibilities.<br>
If you take a look at the mx.rpc.AsyncToken you can see that this
class provides a lot of infrastructure based data.<br>
Why should a command be aware of it?</p>
<p>It is really interesting that a lot of frameworks like
cairngorm, parsley, ... are talking about layers, separation of
concern etc., but nobody of them is doing it the right way in my
opinion.</p>
<p>Hannes</p></div>Hannestag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-13T09:27:07Z2011-05-13T09:27:07ZService - Promise/Asynctoken Handling<div><p>hannes answer makes perfect sense to me.</p>
<p>i would opt for a similar call like this:</p>
<p>`function serviceCall(responder:IResponder,
query:String):void</p>
<p>I'm just wondering if I'm digging in some weird scenarios and
nobody else was thinking about this before... as Hannes mentions:
The Parsley Framework Doku kinda recommends this approach with
handing out an asynctoken to a command.</p></div>egotag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-13T09:33:41Z2011-05-13T09:33:41ZService - Promise/Asynctoken Handling<div><p>I'm obviously missing something because I can't see the
different except in who has responsibility for creation.</p>
<p>I'd use promises (check out Shaun's oil utils) instead of the
AsyncToken - but the purpose of the token is that it simply
represents a way to get the result in the future. Whether the
response is synchronous or asynchronous shouldn't matter - the
promise should be smart enough to deliver its result instantly if
the handlers are added afterwards (which I guess is your
concern?)</p>
<p>That said, I tend to go for the standard event approach myself,
so maybe I'm not digging the detail?</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-13T10:18:13Z2011-05-13T10:18:13ZService - Promise/Asynctoken Handling<div><p>"the promise should be smart enough to deliver its result
instantly if the handlers are added afterwards (which I guess is
your concern?)"</p>
<p>correct! is this would be a concrete solution for what I was
actually lookin for... and actually one way to answer my question:
"Smarten up your tokens!"</p>
<p>I will think about it! :)</p></div>egotag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-13T11:18:09Z2011-05-13T11:18:09ZService - Promise/Asynctoken Handling<div><p>I'm glad that made sense!</p>
<p>Part of the problem is that we suffer availability-bias in our
thinking due to the language constructs, when really our intention
is important.</p>
<p>When we do something like:</p>
<pre>
<code>dataDeliveryToken.addEventListener ( DataEvent.DATA_DELIVERED,
dataDeliveredHandler );</code>
</pre>
<p>we <em>think</em> we're listening for an Event. But actually,
from an intent point of view, we're saying:</p>
<pre>
<code>dataDeliveryToken.notifyMeWhenDataIsDelivered_using (
dataDeliveredHandler) ;</code>
</pre>
<p>Now - if the data has already been delivered, it's only sensible
that the asyncItem would say "Oh, actually it's here already - here
you go!" and run the handler immediately.</p>
<p>Order of operations and race conditions problems are issues of
language / compiler / runtime detail - it's annoying that we have
to work around them sometimes, but I think the starting point
should always be "What's my intent? What makes sense? How would I
describe this relationship / process / request in words?" and then
work from there.</p>
<p>It's one of the reasons why it's nice to work in a few different
languages - it starts to show you what hoops the specific language
makes you jump through!</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-13T11:51:19Z2011-05-13T11:51:20ZService - Promise/Asynctoken Handling<div><p>Is there a Promise implementation for RemoteObject ?</p></div>Fabientag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-13T12:34:28Z2011-05-13T12:34:29ZService - Promise/Asynctoken Handling<div><p>@Stray</p>
<p>How do you manage command sequencing if you dispatch events from
your services ?<br>
I tried to follow your service/dispatchEvent way, but I get stuck
when using services calling commands which are used in a startup
sequence and also independently on user actions.<br>
Example :<br>
I want to get a list of albums a user own at startup, among other
sequenced requests and also use this command when a user click to
see his friend's albums.</p></div>Fabientag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-16T06:44:02Z2011-05-16T06:44:02ZService - Promise/Asynctoken Handling<div><p>This might be a product of convenience but I have always just
implemented the IResponder interface on my service-calling command.
Then, as ego seems to do, I send a reference of the command to the
service. Then the command handles the result/fault. From here I can
operate on the injected model or chain other commands to the
response.</p>
<p>In terms of caching, my commands sometimes check for the
existence of data (model or entity cache manager) to determine
whether to call the service to just call the result handler
directly with cached data. You can also throw in some event
properties to force a refresh of cached data.</p></div>Tony Smithtag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-25T08:20:07Z2011-05-25T08:20:07ZService - Promise/Asynctoken Handling<div><p>@Fabien</p>
<p>sorry - missed your response there.</p>
<p>I'm not sure I've had to solve the specific problem you're
describing, but I do use a command queuing util
(DeferredCommandMap) which is solving a similar problem for me.</p>
<p>My 'similar' problem is that I have an administrator tool which
is used to edit remote data. The tool can do many different things,
and usually the administrator only wants to do one task. There are
multiple tabbed screens that each represent a task "Manage users /
manage groups " etc. Most screens require more than one data set,
and many of the screens have overlaps in what they require.</p>
<p>The user manually initiates loading for the screen they want to
use (they click a big button saying "load data for this screen) and
then all the required data types are queued for loading.</p>
<p>Does that sound similar?</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-05-25T11:15:07Z2011-05-25T11:15:09ZService - Promise/Asynctoken Handling<div><p>Hi Stray,</p>
<p>I looked up DeferredCommandMap code but I don't think it covers
my needs. I need a sequence to stop in case of an error in the
service or a result.<br>
Typically, what I want is :<br>
- I validate the user session - then I log the user (I could merge
with the above) - then I start loading specific stylesheets bundles
and modules - then I get some data from the server</p>
<p>Moreover, I want to display a friendly error message in case any
of these return a fault or an invalid result, and stop the sequence
here.</p>
<p>In order to do that I transformed all my Commands into
AsyncCommand and I handle the result/fault in the command.<br>
Example :</p>
<pre>
<code>// ValidateUserSessionCommand extends AsyncCommand
[Inject]
public var event:UserEvent;
override public function execute():void
{
trace(this, "execute");
service.validateUserSession(event.userVO.id)
.addResponder(new Responder(onResult, onFault));
}
private function onResult(event:ResultEvent):void
{
var success:Boolean = remoteResultProcessor.processResult(event);
if(success)
{
// update model..
}
dispatchComplete(success);
}
private function onFault(event:FaultEvent):void
{
remoteResultProcessor.processFault(event);
dispatchComplete(false);
}
override public function dispatchComplete(success:Boolean):void
{
if(success)
{
trace(this, "complete");
}
else
{
trace(this, "error");
dispatch(new ErrorPopupEvent(ErrorPopupEvent.POP_ERROR, "Friendly error message..));
}
super.dispatchComplete(success);
}</code>
</pre>
<p>From there, I use Macrobot's SequenceCommand :</p>
<pre>
<code>// StartupCommand extends SequenceCommand
override public function execute():void
{
trace(this, execute);
this.atomic = false;
var userVO:UserVO = new UserVO();
userVO.id = appParams.userId;
var userEvent:UserEvent = new UserEvent(UserEvent.VALIDATE_USER_SESSION, userVO);
this.addCommand(ValidateUserSessionCommand, userEvent, UserEvent);
userEvent = new UserEvent(UserEvent.GET_USER, userVO);
this.addCommand(GetUser, userEvent, UserEvent);
this.addCommand(LoadStyleSheet, "shared", String);
this.addCommand(LoadResourceBundle, "shared", String);
super.execute();
}</code>
</pre>
<p>I have sequence + standalone reusable commands in other part of
the app. Though it's not the best architecture, it feels nice to
me... but before you bring out the whip, let me say I am opened to
anything better :p</p></div>Fabientag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-06-07T13:24:27Z2011-06-07T13:24:27ZService - Promise/Asynctoken Handling<div><p>No whip! No whip!</p>
<p>Yes - you're using your commands as a macro where each command
is dependent on the success of the previous one. It's not a problem
I've had to solve so I'd say that if your solution is working then
it's valid!</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-09-30T01:55:54Z2011-10-12T10:16:56ZService - Promise/Asynctoken Handling<div><p>I realise this is Robotlegs but we can always learn from other
places. I have found a nice implementation in PureMVC, apart from a
normal SimpleCommand and MacroCommand, there is also
AsyncMacroCommand where elements are AsyncCommand. Instances are
required to call commandComplete() which lets the macro command
know when it has completed, and the next command can continue. If
an AsyncCommand fails, it doesn't call commandComplete() and
execution stops at that point in the chain. see <a href=
"http://puremvc.org/pages/docs/AS3/Utility_AS3_AsyncCommand/asdoc-standard/org/puremvc/as3/patterns/command/AsyncCommand.html">
http://puremvc.org/pages/docs/AS3/Utility_AS3_AsyncCommand/asdoc-st...</a></p></div>hipitihoptag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-09-30T05:52:14Z2011-09-30T05:54:50ZService - Promise/Asynctoken Handling<div><p>In case you're using signals you could also try out my
SignalResponder class<br>
<a href=
"https://github.com/creynders/SignalResponder">https://github.com/creynders/SignalResponder</a><br>
(I'm sorry for the blatant self-promotion, but I wrote it because I
had use for it, maybe others do too) Unfortunately at the moment
you'll have to pass the signalresponder instance to the service
instead of letting the service create it, since signals aren't
"smart enough to deliver its result instantly if the handlers are
added afterwards"<br>
You could however use it in combination with my RelaxedSignals
addition to the Signals lib:<br>
<a href=
"https://github.com/creynders/as3-signals">https://github.com/creynders/as3-signals</a><br>
I'm trying to get it pulled into the official lib, but have had no
response from Robert Penner yet.</p>
<p>-EDIT- Hmmm, this is an old thread. I didn't notice that when I
wrote the reply.<br>
Tender works in mysterious ways.</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-09-30T07:22:46Z2011-09-30T07:22:46ZService - Promise/Asynctoken Handling<div><p>Ah! Awesome - I had started work on a relaxed signal - but
you're already there. Super!</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-09-30T17:19:57Z2011-09-30T17:19:57ZService - Promise/Asynctoken Handling<div><p>@stray If you got the time, all feedback on the RelaxedSignals
is very welcome!</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/71890792011-10-07T12:58:23Z2011-10-07T12:58:23ZService - Promise/Asynctoken Handling<div><p>If anybody lands here looking for info on RelaxedSignals, here's
a link to the demo:<br>
<a href=
"http://www.creynders.be/2011/10/06/relaxedsignals/">http://www.creynders.be/2011/10/06/relaxedsignals/</a></p></div>creynders