(Migrated) Retrieving results of service invoked with invoke_async

(This message has been automatically imported from the retired mailing list)

Hi,

The docs show how to initiate process in “other service” asynchronously and
get Correlation ID (cid) in exchange.

The other service most probably will assign its self.response.payload with
some kind of result. Where that result will land to? How can I get it with
cid I have in original invoking service? How can I know that the result is
ready? Should I poll some storage (Redis?) occasionally?

Can I wait for result instead of polling?

Regards,

Myroslav Opyr

Hi there,

The docs show how to initiate process in “other service” asynchronously
and get Correlation ID (cid) in exchange.

The other service most probably will assign its self.response.payload
with some kind of result. Where that result will land to? How can I get
it with cid I have in original invoking service? How can I know that the
result is ready? Should I poll some storage (Redis?) occasionally?

Can I wait for result instead of polling?

As far as waiting goes - this can be only done when using regular
.invoke instead of .invoke_async, the latter never waits for anything.

The thing to do in your situation is to split the first service’s
functionality into two.

A flow would be such as:

  1. service1 invokes_async service2 receiving CID on output
  2. service1 stores CID in Redis along with any other context needed to
    continue processing later on
  3. service2 does its job and invokes_async (or simply invokes) service3
    passing along CID it was originally invoked with
  4. service3, having received CID, looks up the CID in Redis, gets all
    the context needed and continues the flow where service1 left off

This assumes that step 2) is completed before 3) - but I understand 3)
does a long-running job or something similar and this is why you need to
invoke it asynchronously.

So CID really can be used as a Correlation Identifier. For anyone coming
from the EIP (Enterprise Integration Patterns) - this is the same thing
as http://www.eaipatterns.com/CorrelationIdentifier.html

Zato implements/supports/offers other EIPs as well, I just didn’t have
time to document it all properly yet. But a chapter on that will be
added, that’s for sure.

Hi there,

The docs show how to initiate process in “other service” asynchronously
and get Correlation ID (cid) in exchange.

The other service most probably will assign its self.response.payload
with some kind of result. Where that result will land to? How can I get
it with cid I have in original invoking service? How can I know that the
result is ready? Should I poll some storage (Redis?) occasionally?

Can I wait for result instead of polling?

As far as waiting goes - this can be only done when using regular
.invoke instead of .invoke_async, the latter never waits for anything.

The thing to do in your situation is to split the first service’s
functionality into two.

A flow would be such as:

  1. service1 invokes_async service2 receiving CID on output
  2. service1 stores CID in Redis along with any other context needed to
    continue processing later on
  3. service2 does its job and invokes_async (or simply invokes) service3
    passing along CID it was originally invoked with
  4. service3, having received CID, looks up the CID in Redis, gets all
    the context needed and continues the flow where service1 left off

This assumes that step 2) is completed before 3) - but I understand 3)
does a long-running job or something similar and this is why you need to
invoke it asynchronously.

So CID really can be used as a Correlation Identifier. For anyone coming
from the EIP (Enterprise Integration Patterns) - this is the same thing
as http://www.eaipatterns.com/CorrelationIdentifier.html

Zato implements/supports/offers other EIPs as well, I just didn’t have
time to document it all properly yet. But a chapter on that will be
added, that’s for sure.

A flow would be such as:

  1. service1 invokes_async service2 receiving CID on output
  2. service1 stores CID in Redis along with any other context needed to
    continue processing later on
  3. service2 does its job and invokes_async (or simply invokes) service3
    passing along CID it was originally invoked with
  4. service3, having received CID, looks up the CID in Redis, gets all
    the context needed and continues the flow where service1 left off

This assumes that step 2) is completed before 3) - but I understand 3)
does a long-running job or something similar and this is why you need to
invoke it asynchronously.

Now that I have read - I think a good feature to add would be to have
invoke_async optionally store the CID/context itself /prior/ to actually
invoking 3).

This way it would be guaranteed that 3) doesn’t complete before context
is in Redis.

Right now you need to calculate ‘does 3) take long enough for Redis to
store everything’. It probably takes 0.01 ms for Redis to do its job and
3) may take several seconds or minutes but naturally, this isn’t ideal.

Sounds a good thing to add?

For example I’d like to use invoke_async to be able to parallelize
execution of services and use their results in my actual service results.

Something like sleep(10) is safe in gevent-powered environment. And I
see no problem in keeping state in local variables of my master service
that does number of invoke_async calls.

What I’d need is to have something as simple as self.async_ready(cid)
and self.async_get(cid) to wait for result and to retrieve the results
of async service. Something closer to Python synchronization objects
would be preferable.

Ah, OK. I didn’t catch you need to invoke_async multiple services. Such
a fan-out/fan-in scenario is not a built-in right now. This is a
desirable feature and I know what you mean, it’s just there’s no such
thing right now.

If you’re OK with sleep()-ing yourself then I think this is the only way
to do it now manually. You’d need to invoke_async as many services as
you need and sleep() yourself periodically checking if answers are there.

Sorry, this is the only way to do it. But it is another good pattern to
add and it will be done.

Hi,

The scenario with 3 different services and Redis complicates scenario a
lot. The service2 would have to determine the way it is invoked and produce
result in different ways (i.e. not self.response.payload). I’d like for
service to be invocation-style agnostic.

For example I’d like to use invoke_async to be able to parallelize
execution of services and use their results in my actual service results.

Something like sleep(10) is safe in gevent-powered environment. And I see
no problem in keeping state in local variables of my master service that
does number of invoke_async calls.

What I’d need is to have something as simple as self.async_ready(cid) and
self.async_get(cid) to wait for result and to retrieve the results of async
service. Something closer to Python synchronization objects would be
preferable.

Regards,

Myroslav Opyr

On Thu, May 30, 2013 at 3:40 PM, Zato community’s mailing list <
zato-discuss@lists.zato.io> wrote:

Hi there,

The docs show how to initiate process in “other service” asynchronously

and get Correlation ID (cid) in exchange.

The other service most probably will assign its self.response.payload
with some kind of result. Where that result will land to? How can I get
it with cid I have in original invoking service? How can I know that the
result is ready? Should I poll some storage (Redis?) occasionally?

Can I wait for result instead of polling?

As far as waiting goes - this can be only done when using regular .invoke
instead of .invoke_async, the latter never waits for anything.

The thing to do in your situation is to split the first service’s
functionality into two.

A flow would be such as:

  1. service1 invokes_async service2 receiving CID on output
  2. service1 stores CID in Redis along with any other context needed to
    continue processing later on
  3. service2 does its job and invokes_async (or simply invokes) service3
    passing along CID it was originally invoked with
  4. service3, having received CID, looks up the CID in Redis, gets all the
    context needed and continues the flow where service1 left off

This assumes that step 2) is completed before 3) - but I understand 3)
does a long-running job or something similar and this is why you need to
invoke it asynchronously.

So CID really can be used as a Correlation Identifier. For anyone coming
from the EIP (Enterprise Integration Patterns) - this is the same thing a=
s
http://www.eaipatterns.com/**CorrelationIdentifier.html<http://www.eaipat=
terns.com/CorrelationIdentifier.html>

Zato implements/supports/offers other EIPs as well, I just didn’t have
time to document it all properly yet. But a chapter on that will be added=
,
that’s for sure.

On 05/30/2013 04:16 PM, Zato community’s mailing list wrote:

Will Zato automatically put service2 response.payload somewhere for
service1 to retrieve given service1 has only cid and it waited long
enough for that result.payload to be calculated and stored?

Nope. When using invoke_async you get a CID because you invoke it
completely asynchronously.

The way it is implemented now is:

  1. s1 invokes_async s2
  2. a CID is generated
  3. a message is published on Redis for s2 to be invoked with this CID

[at this moment s2 can be anywhere, on a different server across the
globe and has no way to return anything to s1 directly]

  1. s1 receives the CID
  2. s2 is invoked, possibly on a different server, in a different
    OS-level process

So I understand the desire to have a unified API for any sort of
invocations and like I said, it sounds a good idea to add it, but it’s
just not there yet.

When using invoke_async you get a CID because you invoke it
completely asynchronously.

Sorry - I meant ‘you get a CID and nothing else’ - s1 and s2 are
completely disconnected.

It was designed in such a way to avoid any blocking (s1 waiting for s2
in a blocking manner, even if using gevent, but still) but I see some
use cases are OK with it.

Will Zato automatically put service2 response.payload somewhere for
service1 to retrieve given service1 has only cid and it waited long enough
for that result.payload to be calculated and stored?

On Thu, May 30, 2013 at 4:23 PM, Zato community’s mailing list <
zato-discuss@lists.zato.io> wrote:

For example I’d like to use invoke_async to be able to parallelize

execution of services and use their results in my actual service results.

Something like sleep(10) is safe in gevent-powered environment. And I
see no problem in keeping state in local variables of my master service
that does number of invoke_async calls.

What I’d need is to have something as simple as self.async_ready(cid)
and self.async_get(cid) to wait for result and to retrieve the results
of async service. Something closer to Python synchronization objects
would be preferable.

Ah, OK. I didn’t catch you need to invoke_async multiple services. Such a
fan-out/fan-in scenario is not a built-in right now. This is a desirable
feature and I know what you mean, it’s just there’s no such thing right now.

If you’re OK with sleep()-ing yourself then I think this is the only way
to do it now manually. You’d need to invoke_async as many services as you
need and sleep() yourself periodically checking if answers are there.

Sorry, this is the only way to do it. But it is another good pattern to
add and it will be done.


Dariusz Suchojad

https://zato.io
The next generation ESB and application server. Open-source. In Python.
_____________**
Zato-discuss mailing list
Zato-discuss@lists.zato.io
https://mailman-mail5.**webfaction.com/listinfo/zato-**discusshttps://mailman-mail5.webfaction.com/listinfo/zato-discuss

On 05/30/2013 05:16 PM, Zato community’s mailing list wrote:

[…]

This scenario would let developer develop her Services for invocation by
sync and async approaches uniformly (by assigning result to
self.response.payload) and finishing execution of handle function

Yup, this sounds very good. This is how it should look like, agreed.

I’m doing minor things that will go into 1.1 some time soon but in
future versions what you describe will be handy indeed. :slight_smile:

An unrelated note though is that you can keep/retrieve the
context/response by using SQL, AMQP, ZeroMQ, WMQ or really any other
medium. It’s just Redis is the most convenient one. Just a side note.

  1. s1 invokes_async s2
  2. a CID is generated
  3. a message is published on Redis for s2 to be invoked with this CID

[at this moment s2 can be anywhere, on a different server across the globe
and has no way to return anything to s1 directly]

  1. s1 receives the CID
  2. s2 is invoked, possibly on a different server, in a different OS-level
    process

I’d like to continue the list.
6) s2 does its work and assigns self.response.payload as it normally does,
and finishes its handle() processing
7) Zato stores the result as s2. keyed entry in Redis (as it is the
only Zato’s persistence and messaging medium). This place can be the same
that synchronous invoke() uses.
8) s1 either though polling of Redis (by CID) or through some kind of
subscribe/wait mechanism reach to this point of time
9) s1 retrieves result of s2 execution from Redis

This scenario would let developer develop her Services for invocation by
sync and async approaches uniformly (by assigning result to
self.response.payload) and finishing execution of handle function

This scenario would let developer save time by parallel execution of
different services with async approach.

This would reduce amount of code and architectural steps if developer
choose async approach.