Optimizing BAM Performance with API Management
Tags: azure, api
Published: 2023-02-06 17:45:46

In a previous article, I discussed how you could use API Management as a proxy for the Serverless360 BAM API. In the real world, I have used this approach a few times because I prefer it to the custom connectors that you can use with Logic Apps which are sometimes painful to use from a DevOps perspective and have known performance limitations that can affect the latency and throughput for connections Logic Apps make to Cloud Services.

Using APIM as a proxy overcomes those bottlenecks and gives me several other benefits such as key management which we have discussed previously.

What a few customers have asked about previously is if they can minimize as much as possible the latency impact in their Logic Apps when they want to use BAM. The latency involves in the BAM API is that when your Logic App (or another component) pushes a message to the BAM API we save the message to a queue on Service Bus behind the scenes so that we can then process the message out of the process and do the work of matching to a transaction, etc. The BAM API can have that latency from the call to your Logic App to the API and then persist the message to the Queue.

One of the things that some customers have done is to use either the HTTP action or APIM Action in the Logic App which takes the custom connector out of the call. This is the first performance optimization you can do if you want to tune your scenario to reduce latency.

If you want to tune things so that you can get even lower latency, then an approach I have used is to take advantage of the send-one-way-request policy in API Management. This allows me to send a normal request from my Logic App to BAM via API Management but inside the policy, I will then use the send-one-way-request to forward the message to BAM and return a response. This means that APIM will respond super quickly to your Logic App so you can continue processing.

**What does this look like?**

If we consider a sequence diagram showing the typical flow of a Logic App consuming the BAM API, it will look like the below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3h8cp3dyen8tixz3mk3y.png)

In this case, each time the Logic App calls BAM it waits until the message is persisted for processing and then continues.

By putting APIM between the Logic App and BAM we can use a sync to async pattern and the call to the Logic App will return quickly so the Logic App can continue processing. The call to the BAM API will then be done in the background out of the process as shown below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2pkt2emltbz9wej7mwxa.png)

**Design Decision**

When you choose to use this sync to async process you do need to be aware that you will be making a trade-off. When you use the API directly you can be sure that the message got persisted and will appear in BAM before you continue processing the Logic App. By using the sync to async approach you accept that if there is an error between APIM and the BAM API then your Logic App will not be aware of this error.

In BAM we chose to use Service Bus for reliability and guaranteed at least one processing of messages and the advanced dead letter and error support, but if you have a scenario where you are willing to accept that in an error condition you don’t mind the risk that you may lose a BAM event then this sync to the async pattern will remove the latency of the BAM API and the Logic App connector from your Logic App processing duration.

**Approach**

With the approach for this pattern, we will import the API Definition for BAM into API Management as we did in the previous article however this time, we will clone the StartTransaction and CheckPoint operations and create two additional ones called StartTransaction-Async and CheckPoint-Async. This will allow us to use the out-of-the-box approach for the cases where we want to be sure BAM has the message before continuing and we can use the async ones where we are ok to risk potential message loss so we can reduce the latency.

**Walk Through**

At the start of the walkthrough, I am assuming you have imported your BAM API definition into API Management as demonstrated in the previous article about using APIM as a proxy to BAM.

**Add Sync to Async API Operations**

Next, we will add the cloned operations. You can use the Azure Portal to clone an operation by right-clicking on it as shown in the picture below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k0ofwmmcznncd2dh0dp8.png)

We will then go and modify the name and path for the operation in the operation settings.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ur7yaytfp2i5adiloyv6.png)

You will want to modify the name that Azure sets by default when cloning the operation and the URL path. I chose to just add a suffix of -Async on them.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y57qsm888plhwf3hn7us.png)

You will need to repeat these steps, so you have set up both StartTransaction and CheckPoint with async versions.

**Set Policy**

For each operation, you will need to modify its inbound policy to do a send-one-way request and then return a response. This is shown in the samples below. Note that I set the BAM URL and API Key as named values, so they are easy to access in the policy.

**Start Transaction Async**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wd6e0uvozkujdlqciws.png)

**CheckPoint Async**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xfkus0t6mtyiv1dpflgc.png)

**Logic App Setup**

In my Logic App you will see if I access API Management and choose my BAM API there are additional operations available so I can use the async versions of the operations.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mat5fnkbzi4rxzg8z9vm.png)

When I use the operations the one key difference you need to be aware of is that we have added a new property on the StartTransaction so you can supply your guid when starting a transaction rather than having to wait for the one the BAM API gives you back as shown below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vnip1zk98h9ja2x273kz.png)

In this case, I just create a string variable at the start of my Logic App using the Guid() expression and then reference it when calling BAM.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ki73iuv4y1957mvgcews.png)

You are now ready to use your BAM actions from APIM in your Logic App and you will find that your logic app will take less time to run using the sync to the async pattern.
Comparison

If we do a basic comparison of the time the Logic App takes for the different approaches with three similar logic apps which do 2 BAM actions and return a response where the logic app looks like the below picture, then the comparison is below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/22l4kcz7r85y4g42jm6e.png)

**Logic App with Custom Connector**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xk0rzp5c0zz3dfynhkip.png)

**Logic App with APIM – Sync Pattern**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/by8jpah20ser0lf2tzam.png)

**Logic App with APIM – Sync to Async Pattern**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7jouh50r11ksqoallm2.png)

**Observations**

You can see there is a slight performance benefit from the APIM sync approach in terms of latency compared to the custom connector, but it is not that big. Where APIM offers a benefit here however is that when you have a connector that is shared by a lot of Logic Apps there can sometimes be throttling challenges. This is a common Logic App challenge people have come across with connectors in general for Logic Apps at scale and there are patterns people use with multiple instances of connectors.

With the APIM connector, it does not use a cloud connector in the same way, and you do not get the Azure API Connection resource type created, the APIM action is more like a wrapper over the HTTP action which utilizes discovery from Azure APIM to make it easier to consume the API. For this reason, we should not have the throttling challenges we get with API Connectors. There is a small latency improvement in a basic test but as you scale up id expect a more noticeable benefit.

With the Sync to Async pattern, you can now see a noticeable benefit where the API calls to APIM are significantly quicker demonstrating we can make our Logic App run much faster if we need to.

**Summary**

Hopefully, this article shows it is easy to use APIM to help implement more advanced scenarios with the BAM API where you can tune the performance of your interfaces when you need to have lower latency requirements, but still want to use the cool operational features of our BAM solution.