Question
· Mar 17, 2017

Custom Business Process. Change from SendRequestSync to SendRequestAsync

I have a number of Business Process and due to the complexity these were created as "custom code" instead of BPL.

These processes currently invoke other components using SendRequestSync. For a couple of reasons I would like to be able to change these to use SendRequestAsync:

  • a long running BusinessOperation (often over 45s) calling an external system has caused pool sizes to be increased to compensate. This operation is a real time request for the entire health record held for a patient.
  • with the above operation, a different webservice method can be called that allows partial health record to be requested. In theory with this approach the external service will be quicker and we can request multiple parts of that health record to process in parallel. The current Business Process will need to collate the responses.

The available Ensemble docs I can find do not cover parallel/async calls when extending Ens.BusinessProcess. The closest example I can find is HS.Gateway.Access.Manager. I'm familiar enough with multi threading from other languages such as Java but not with Cache Object Script/Ensemble. I think what I need to do is in the pseudo code below. Can anyone provide advice or better still an example?

Couple of things I'm not sure of:

  • what is pCompletionKey  used for? Can that be used as a unique reference for that invocation of SendRequestAsync?
  • Is there such a thing as a sleep "Status" to use as Quit for OnRequest? Or do I need to loop until done? Will HANG in this case release the resources used by the process?
  • if the target operation responds with an error is that handled by OnResponse or only OnError?

cheers

 Method OnRequest(request As %Library.Persistent, Output response As %Library.Persistent) As %Status
{
//lock the global with unique id (e.g. session id) and component name.
//for each async method call
//    add response key to the global for each async call. 
//release the lock

//loop.
//    Quit the loop if all response received (or possibly after timeout??)
//    else hang for a minimal period (e.g. tenth of second)

//quit with the result of all responses
}
 Method OnResponse(request As %Library.Persistent, ByRef response As %Library.Persistent, callrequest As %Library.Persistent, callresponse As %Library.Persistent, pCompletionKey As %String) As %Status
{
//lock the global created in OnRequest
//update the global with a completion status

<span style="font-size:10px;"><font color="#008000">//release the lock</font>
<font color="#000000">}</font></span>
Discussion (5)0
Log in or sign up to continue

As the implementor of the BPL engine I would caution against this approach.  There is an awful lot of book keeping you have to do to which is better handled by BPL. A technique which has worked well for me in the past is to create a context class which contains much of your logic and then reference that in a simple BPL which performs the calls asynchronously. This is done by setting the 'contextsuperclass' attribute on the BPL process element in the XDATA block. The BPL compiler will use th e named class as the superclass of the context class which it generates during the compilation phase.

Hi,

Ensemble has a piece of infrastructure to handle parallel calls. Here's how to run it:

for tCounter = 1:1:10 {
   set tCall = ##class(Ens.CallStructure).%New()
   set tCall.TargetDispatchName = ”MyBusinessHostClass"
   set tCall.Request = ##class(MyRequestClass).%New()

   set tCall.Request.MyProperty = "Some value"
   set tRequestList(tCounter) = tCall
}
set tTimeout = 10
set tSC = ..SendRequestSyncMultiple(.tRequestList, tTimeout)

After that finishes, you can access the individual responses like this:

for tCounter = 1:1:10 {
   set tStatus = tRequestList(tCounter).ResponseCode
   set tResponse = tRequestList(tCounter).Response
}

Hope that's what you're looking for,

Otto

Couple of things I'm not sure of:

  • what is pCompletionKey  used for? Can that be used as a unique reference for that invocation of SendRequestAsync?
  • Is there such a thing as a sleep "Status" to use as Quit for OnRequest? Or do I need to loop until done? Will HANG in this case release the resources used by the process?
  • if the target operation responds with an error is that handled by OnResponse or only OnError?

The CompletionKey is a 'tag' which you can attach to each async call. So you can distinguish them in the OnResponse by that tag.

Just 'Quit' the OnRequest, Ensemble will call the OnResponse when needed.

At the end (all Requests have responded or an optional time-out has occurred) the OnComplete will be called.

If the target operation has responded with a error-message in the Response message it will be in the OnResponse.

(I think) the OnError will be called if the target operation exits with a status code of not $$$OK