Often our applications integrate with different APIs. User may click one button but the application will make multiple API calls behind the scenes. That can take time and lead to situations where one API call succeeds but others fail. How can we make the process faster and more reliable?
Here is an example from my day job. I work on online fundraising platform. When users give donations our application calls credit card processor API. If the first transaction succeeds we make another API call to get credit card token which we can store in our system. Then we call SendGrid API to send a receipt.
Here is one way to do this:
Not only is this code difficult to maintain but all 3 API calls have to complete before response comes back to the user. How can we make it better?
We can separate the process into tasks that must be done immediately and tasks that can be done in the background shortly thereafter. Ruby on Rails provides ActiveJob framework but other languages have similar solutions.
The second API call to
tokenize_card is now done via background job so we grab the
donation record in the DB (or we could pass it as parameter to the job).
For the 3rd API call to SendGrid API Rails ActionMailer provides a handy
deliver_later method. The email will be automatically thrown in the queue and picked up by background job. But we could build the job ourselves and call it from
CreditCardProcessor like this
SendReceiptJob.perform_later(donation) if the charge succeeds.
To go even further we could do the initial credit card processing request in the background but that would require changing UI to use long polling or ActionCable to refresh when the first job completes.
But what happens when these background API calls fail? That depends on what they do. If sending email receipt times out the on the first request the job framework will usually automatically retry it which is fine. But there could be situations where we do not want to retry it. Or perhaps we would need to build monitors to alert biz users / sysadmins when the background jobs get backed up too much or had too many errors.
Other APIs and client libraries will have methods and parameters different than
transaction_id. And the examples are above are highly oversimplified. They are meant to illustrate a pattern of how by breaking up big tasks into smaller ones we can execute them separately.