1

We maintain an API that as part of its purpose makes a call to an external API. This external API takes a few seconds to fulfil the request we make to it. With our current architecture the request is made synchronously, meaning that the http response we return to the user request is blocked until our service get the response from the external API.

I am considering changing our architecture to be able to deal with the request asynchronously... By this I mean accept the user request into our API and put a message on a queue so that we return an http response a lot quicker. The response would contain the address of where the full/complete result can be found. A background task would then pick messages up from the queue and make the call to the external API, then store the result at the address provided in our response. The address could then be polled by the user/client until the desired state of the respource is reached (i.e. when the background task has finished calling the external api and has stored the result).

This architecture I have mainly lifted from the REST in Practice book. The crux however is that our external API only takes 2-3 seconds to return the response. The example in the book describes an ordering process that might take minutes or hours. Is this suggested solution worth the increase in complexity for such a short response time from our external dependency? i.e. will the application still scale with the existing synchronous architecture?

3 Answers 3

2

The situation you're describing (using queues and polling) will definitely work, but as long as your external API takes only a few seconds to return a response, I think there's an easier way:

As you described, it's a good idea to have your webpage response not include the data from the external API, because this allows the page response to be sent more quickly. I would make the call to the External API as follows:

  • The response page contains a piece of javascript that makes an asynchronous AJAX call to a REST endpoint on your website.
  • Your REST endpoint calls the external API, and just blocks until it receives the response. Once it receives the response, it returns the results to the caller (i.e. the browser that executed the AJAX call).
  • When the response page javascript receives the data from the AJAX call, it displayes the results by manipulating the HTML DOM of the response page.

This way, the only thing that needs to be async is the AJAX call from the browser; this effectively starts a new 'background thread', and the calls that are run in this thread (from browser, to your REST endpoint, to external API, and then back again) can all be executed synchronously.

Obviously, this only works as long as the external API returns its responses fast enough (under a minute or so), otherwise the synchronous calls will time out. As long as you're confident that this is the case, I think this solution is less complicated while still meeting your requirements.

1

There is nothing in REST that stops you from mixing synchronous and asynchronous solutions per resource and method combination.

For example in our query server we return almost everything synchronously as the resources/information are readily available. Only when a new query is posted, do we go the route of generating an identifier and returning an "Accepted" or "See other" (303) response with the URI of the query results resource in the body as well as the location header. Returning information about the query and the query results themselves is done synchronously again.

update

Don't have any numbers on the average delay before result data is available for a posted query. We are still working on the REST implementation. However, queries in our current architecture usually take milliseconds to complete (we are sort of an in-memory database), though we have customers where some queries are known to take 20 minutes to return a result. So in a sense the need for asynchronicity isn't so much the average delay, but the fact that we do not want to have any requests that could block a connection for any serious period of time (> 1 second or so) and customers can post queries that run for more than that.

To give a few more details on the asynchronous execution of queries:

  • The "query result" is a resource that holds the basics about the results of a posted query: identifier, status (progress), uri for the result data (empty / absent until that is available), those kinds of things.
  • The new "query result" resource is stored immediately and before the response to the POST is returned.
  • The query process updates the "query result" with its progress and ultimately with the total number of rows in the result data.

In other words: the new "query result" resource is queryable as soon as the POST returns. It just isn't complete yet. Polling the query result will show status and progress and once the query process finishes, status will be finished and the uri for the result data will have a value.

2
  • That sounds much like what I plan to do. What is your average delay between accepting a request for a new query and storing the new resource in the database so that they are accessible to the client?
    – Nick
    Commented Jul 17, 2013 at 11:30
  • @Nick: see update Commented Jul 17, 2013 at 17:21
0

If you really want to separate for whatever reason the current workflow from where the result is presented, you could use the links-section in the JSON-Response.

{
    "name": "currentStep",

    ...

    "links": [ {
        "rel": "self",
        "href": "/api/job/currentStep"
    },
    {
        "rel": "previousStep",
        "href": "/api/job/previousStep"
    },
    {
        "rel": "result",
        "href": "/api/job/result"
    }
     ]
}

This indicates where you are now, where you were before and where the result is going to be. Implementing it this way, you signal your intention, that the result is under a different location. So the problem of waiting at the current step for results is solved.

What is not covered with this solution is the problem, that neither you nor the user of your API knows, whether there are results at all or when the results will be available under the given URL. So your overall problem is not solved, it is only deferred. When the URL (in my example /api/job/result) is called, it is not sure, whether there is a result or not.

On the one hand, you have a synchronous servicecall, which lasts 2-3 seconds on average, after which you return the result to the user without interruption of the flow or on the other hand a possible gap but immediate answer.

Without further knowledge of the overall architecture and your userbase it is hard to say anything. How critical are 2-3 seconds? In the finance-sector it may be mission-critical in other sectors it may be neglectable.

Another solution comes to my mind, but for that, I have to know more of your application infrastructure:

If there are more service-calls needed, you could make them all asynchronous. Say you have the following setup:

To comple the whole request you have to do steps A,B.C and D. D in this case is, the call to the external service, which takes 2-3s. So if you do them all in order, you have Step A taking 0.5s, B 0.5s and C 0.5s. Thats 1.5s. To which the 2s of call D is added. That makes overall 3.5s to wait.

If you do them all in parallel, you only have to wait for the slowest. In this case, that would be 2s which is significantly faster.

Not to mention long-polling / comet ("oldschool") or websockets. With e.g. websockets you have the possibility to push the result from the server down the pipe as soon as you have it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.