Parallel execution lets services invoke an arbitrary number of other services providing a set of callback services to be executed after each of the targets completes.
Target services run in parallel, asynchronously, and are not notified of each other’s execution progress. All of the callbacks configured also run asynchronously without blocking each other.
The diagram below depicts the feature in its full scope. 3 target services are executed, each runs independently, each with a list of their completion callbacks.
In the most common case, the usage will be as follows. A dictionary mapping targets and their requests along with a list of callbacks is provided to self.patterns.parallel.invoke. All of the targets are invoked in background and, once they all complete, each of the callbacks is invoked.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from zato.server.service import Service
class MyService(Service):
def handle(self):
# A dictionary of services to invoke along with requests they receive
targets = {
'service1': {'hello':'from-parallel-exec1'},
'service2': {'hello':'from-parallel-exec2'},
}
# Callbacks to invoke when each of the services finishes
callbacks = ['my.callback1', 'my.callback2']
# On output a Correlation ID assigned to the call is returned
cid = self.patterns.parallel.invoke(targets, callbacks)
|
Users can provide their own Correlation IDs to invoke the services with. It is user’s responsibility to ensure the IDs are sufficiently enough and there will be no duplicates, should that happen - results are undefined.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from zato.server.service import Service
class MyService(Service):
def handle(self):
# A dictionary of services to invoke along with requests they receive
targets = {
'service1': {'hello':'from-parallel-exec1'},
'service2': {'hello':'from-parallel-exec2'},
}
# Callbacks to invoke when both services above finish
callbacks = ['my.callback1', 'my.callback2']
# User-provided Correlation ID
cid = '1632-5754-5628-5197'
# CID returned is the one received on input
cid = self.patterns.parallel.invoke(targets, callbacks, cid=cid)
|
A callback is a regular Zato service that is invoked after each of the targets finishes execution, no matter if any raises an exception or ot.
Each callback is invoked asynchronously, in isolation from any other callbacks defined.
Upon execution, each callback’s self.channel attribute will be set to PARALLEL_EXEC_ON_TARGET from zato.common.CHANNEL.
On input, a callback’s self.request.payload attribute will be a Python dictionary with the contents in the format as below:
1 2 3 4 5 6 7 8 9 10 | {
'source': 'parallel1.my-service',
'target': 'my.service1',
'response': 'My response',
'req_ts_utc': '2015-01-19 19:55:45',
'resp_ts_utc': '2015-01-19 19:55:46',
'ok': True,
'exception': None,
'cid': 'K05129BXK5ZJJABJ41CGPEMZG4J6'
}
|
Key | Notes |
---|---|
source | Name of a service originally issuing the parallel execution call |
target | Name of a target service the callback is executed for |
response | Response the service produced |
req_ts_utc | When was the initial parallel execution call issued, in UTC |
resp_ts_utc | When was the response created, in UTC |
ok | True/False depending on whether the call was successful (raised no exceptions) or not |
exception | Exception’s traceback as string, if ok is not True |
cid | Correlation ID the service was given to its self.wsgi_environ’s zato.request_ctx.parallel_exec_cid key - this is the same CID the source service was given on output from self.patterns.parallel.invoke |
The feature is very similar to the Fan-out/Fan-in pattern - in addition to on-target callbacks from Parallel Execution, Fan-out/Fan-in adds callbacks that are executed only when all of the targets finish.
Jan 18, 2021