Last week, one of our users posted a question about how to get the event ID back to the requesting system when firing through the Integration Agent (note, this article refers to the integration agent, not the xMatters Agent. These are very different technologies so make sure to use the right one for your environment and integration. And consider upgrading to the new agent). This is a great question and I thought it could use the GIG treatment. You might want to have this immediate response when the requesting application requires the event ID for future searching or storing, however, the IA by default will process asynchronously. So read along as we dive into asynchronous vs synchronous responses in the little agent that could.
Send me an email, I'm on the phone
The Integration Agent is a useful tool for making integrations and we’ve already run into this handy agent in a few previous posts (Inbound REST, Making HTTP Calls, and Command Line). Anything that receives web service requests must be built in a robust fashion, after all, it wouldn’t be much good if it fell over when you put a bit of load on it.
One way that the agent is resilient, is through processing incoming web service requests asynchronously. This Stack Overflow post does a good job of explaining the difference between synchronous and asynchronous communications. Here's a nutshell: consider a telephone conversation (synchronous) versus sending a text or email (asynchronous):
- In a telephone conversation, you ask a question and wait for a more or less immediate response from the person at the other end of the call.
- In email, you ask a question and then go make coffee or goof off on the Internet.
The Integration Agent is like the latter: It will acknowledge it has accepted the request and then go off and do other things while a worker process completes the request. This is helpful because it prevents lots of incoming requests from overwhelming the agent and causing it to be delayed in processing further requests. Going back the telephone versus email example, you can only talk to one person on the phone, but you can respond to several emails before you get one answer back.
But I need it now
However, sometimes you need to get information (such as the event ID from xMatters) back from the IA, so you need to force the IA do its work now, not later. To do this, we’ll dive into the apia_http
function in a little more detail. We first ran into this function when making inbound REST calls and it is called with two arguments:
-
httpRequestProperties
- The incoming request object including headers and body. (a wrapper for ServletRequest) -
httpResponse
- The response object to respond back to the http client (a wrapper for ServletResponse)
For the purposes of this article, we are going to focus on httpResponse
. There are only a couple of functions we need for working with this:
-
setHeader
- Sets a header entry. A common header isContent-Type
. -
setStatusLine
- Sets the HTTP Status. This will be one of the 200 or 400 http statuses you’ll see and the originating application can take action based on this value. -
setBodyString
- Probably the most important one as this will contain the “payload” we want to return to the originating system.
So, putting it all together, assuming eventID
contains the event ID returned from xMatters, this is what we end up with:
1.function apia_http(httpRequestProperties, httpResponse) {
2. // .. other stuff to generate an event
3. // .. set eventID
4.
5. // Now, build the response object
6. // First, set the headers
7. var header = new Header("Content-Type", "application/json" );
8. httpResponse.setHeader( header );
9.
10. // We'll return a JSON payload
11. var responsePayload = {
12. "xM Event ID": eventID,
13. "Other Stuff": "Other value",
14. "From Request": requestPayload.item
15. }
16. // The http status code of 200 means A-OK.
17. httpResponse.setStatusLine( HttpVersion.HTTP_1_1, 200 );
18. httpResponse.setBodyString( JSON.stringify( responsePayload ) );
19.
20. ServiceAPI.getLogger().debug("Exit - apia_http");
21.
22. return httpResponse;
23.}
To test this, we can use the handy curl
command. The format for the endpoint exposed by the Integration Agent is:
http://{IA_HOST}:8081/http/{domain}_{name}
Where {domain}
and {name}
are defined in the integration xml file. In this case, httpExample
for both.
An HTTP POST example:
1.curl --request POST --data '{"item": "value"}' "http://localhost:8081/http/httpExample_httpExample"
which returns
1.{"xM Event ID":"12345","Other Stuff":"Other value","From Request":"value"}
or, since this is a generic HTTP endpoint, we can do a GET as well:
1.curl --request GET "http://localhost:8081/http/httpExample_httpExample?item=passed%20in&other=some%20value&stuff=valuable"
which returns
1.{"xM Event ID":"12345","Other Stuff":"Other value","From Request":"passed%20in"}
The key to all of this is the return
at the end of the apia_http
function. If we returned null or did not have a return statement, the agent would process the request asynchronously and the requesting application can continue on merrily. However, since we are explicitly returning a non null value, then the agent processes the request synchronously.
The goods
I’ve attached an example integration service that can be used as a base for building new http integrations that go through the IA and return a custom response. It also contains a parseQueryString
function that will parse the ?&
mess at the end of a GET url. Just unzip it and throw it into the IAHOME/integrationservices directory. Then update the IAHOME/conf/IAConfig.xml file to include this new httpExample in the </service-configs> section, like so:
<path>httpExample/httpExample.xml</path>
Happy Integrating!
8 Comments