6

I'm maintaining a system providing a typical synchronous web service REST API. It routes each request to one of several possible backend services. Now there is a new backend I want to use, but there is a problem - it has an asynchronous API - I will need to do a request, and then wait for a callback request.

I'm thinking that it's possible to hide this asynchronicity behind a syncronizing facade. This facade will call the async API and then put the incoming web requests "on hold". When the callback endpoint is called a few seconds later it will resume the correct web request and respond to the original caller. If the callback does not arrive within let's say 10 seconds I will stop waiting, and respond with an error.

A complicating factor is that I have several web nodes behind a load balancer, but I'm thinking I can use a distributed storage solution like Redis to publish incoming callbacks, so that the correct web node can pick it up.

The question is: Is this feasible? Or do you believe it will be really difficult to get it to work properly? Any experience you can share or links to relevant resources would be much appreciated. Any other aproach to using an asynchronous web service in another service which needs to be syncronous?

Some pseudo code of what I'm thinking:

define rest-endpoint "/foobar" {
    call async backend
    until 10 seconds has passed {
        sleep 1 second
        result = redis.get(some_correlation_id)
        if (result)
            return new Response(result)
    }
    return new Response("failed")
}

define rest-endpoint "/callback" {
    redis.push(some_correlation_id)
}

Note that if I time out and respond "failed" I don't (in my particular case) have to create any kind of compensating transaction towards the backend, and the client is also free to retry the same request later.

For the record: The system is implemented on the .NET stack, but I'm interested in any technology which would make implementing something like this simpler.

Also note that I would probably not actually use sleep in a loop, but some kind of Task / future abstraction.

  • 1
    I'd be curious to see how this is answered, though on the client side, this never ends well. – Jeffrey Sweeney Jan 11 '16 at 22:10
3

I think making clients wait for their web requests is not optimal. Even seconds are too much.

A better way in my opinion is to immediately return the web request, run the asynchronous service and either make the client poll in regular intervals or much better setup a communication channel with the client in the form of websockets for example.

Edit:

Given the new info that the client cannot be changed I think the best approach would be:

Each web node has an instance Id, when you call the async service you give it the endpoint /callback/instanceId and this endpoint calls WebNodes[instanceId].sendResponse().

You need to keep a list of webnodes like that but you don't have to poll redis all the time to see when answer is back, doing poll and thread sleep in a loop is unecessary.

  • Sure, but I don't control the client nor how the front API will look. This is all fixed (been running for years now, Google is one of the consumers, and they dictatet the design). – Torbjørn Jan 12 '16 at 6:06
  • Giving the backend the instanceid is a good idea and might be doable in my case. Thank you! – Torbjørn Jan 12 '16 at 9:20
1

In my programming environment (MacOS X / iOS) it is quite trivial - I create a semaphore, start the asynchronous request, the asynchronous request will unlock the semaphore when it's done, and then I lock the semaphore (which will wake up when the asynchronous request is done). Maybe six or eight lines of code.

On the other hand, synchronous requests, while being easier to handle, have the negative effect that you have to wait for the result, which for anything trying to show a user interface is an absolute no-no. So such synchronous requests should only be used on a background thread.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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