Previous Page Arrow Next Page Arrow

11.5 Asynchronous Operations

The previous method can be made asynchronous. This MUST be reflected in the schema as follows:

  <xs:element name="productComputeSimplePrice" 
              type="tns:productComputeSimplePrice"
              sme:role="serviceOperation"
              **sme:invocationMode="async"** />

The POST request takes an additional trackingID parameter in this case. This parameter MUST be set to a universally unique identifier (UUID) that has been generated by the consumer:

POST /sdata/myApp/myContract/-/products/$service/computeSimplePrice?trackingID=abc42b0d-d110-4f5c-ac79-d3aa11bd20cb 
If the operation is available both in synchronous and asynchronous modes (sme:invocationMode="syncOrAsync"), the presence or absence of a trackingID parameter is used to indicated which mode is requested by the consumer. If trackingID is present, the consumer expects the operation to be processed asynchronously.

The response is very different this time:

202 Accepted
Location: http://www.example.com/sdata/myApp/myContract/-/products/$service/computeSimplePrice('abc42b0d-d110-4f5c-ac79-d3aa11bd20cb')
Content-Type: application/xml
 
<?xml version="1.0" encoding="utf-8"?>
<tracking xmlns="http://schemas.sage.com/sdata/2008/1">
  <phase>Initialization</phase>
  <phaseDetail>Starting thread</phaseDetail>
  <progress>0.0</progress>
  <elapsedSeconds>0</elapsedSeconds>
  <remainingSeconds>7</remainingSeconds>
  <pollingMillis>500</pollingMillis>
</tracking>

The Accepted status code indicates that the server has accepted the request and that it is processing it asynchronously.

The Location header is the URL that the consumer MUST use to track the progress of the operation. Usually, the provider uses the tracking id passed in the POST request to identify the operation (as in the example), but it can also use an internal id. The consumer MUST NOT build the tracking URL itself, it MUST use the value returned by the provider through the Location header.

The sdata: tracking payload indicates the progress in the operation. If the consumer is an interactive application, it MAY test the estimated remaining time to decide whether or not it should display a progress bar. For example, it may decide to show it only if the operation takes more than 5 seconds and only display an hourglass cursor otherwise.

The consumer SHOULD track the progress of the application by sending a GET request on the tracking URL:

GET http://www.example.com/sdata/myApp/myContract/-/products/$service/computeSimplePrice('abc42b0d-d110-4f5c-ac79-d3aa11bd20cb') 

If the operation is in progress, the service provider MUST send a response such as:

202 Accepted
Location: http://www.example.com/myApp/myContract/-/products/$service/computeSimplePrice('abc42b0d-d110-4f5c-ac79-d3aa11bd20cb')
Content-Type: application/xml
 
<?xml version="1.0" encoding="utf-8"?>
<sdata:tracking xmlns:sdata="http://schemas.sage.com/sdata/2008/1">
  <sdata:phase>Computing price</sdata:phase>
  <sdata:phaseDetail>Loading tariffs</sdata:phaseDetail>
  <sdata:progress>20.0</sdata:progress>
  <sdata:elapsedSeconds>2</sdata:elapsedSeconds>
  <sdata:remainingSeconds>6</sdata:remainingSeconds>
</sdata:tracking>
The elapsedSeconds value SHOULD increase between calls. Whereas the progress value MAY NOT always increase and the remainingSeconds value MAY NOT always decrease because the service may adjust its estimates as the operation progresses.

When the operation is complete, the service provider sends the result with an OK status:

200 OK
Content-Type: application/atom+xml; type=entry
 
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>http://www.example.com/sdata/myApp/myContract/-/products/$service/computeSimplePrice?productId=P049&amp;customerID=C027&amp;quantity=5</id>
  <title type="text">computeSimplePrice?productId=P049&customerID=C027&quantity=5</title>
  <updated>2008-03-31T14:52:28Z</updated>
  <sdata:payload>
    <productComputeSimplePrice xmlns="http://schemas.sage.com/myContract">
      <response>
        <unitPrice>120.0</unitPrice>
        <quantityPrice>600.0</quantityPrice>
        <discount>0.0</discount>
        <tax>33.0</tax>
      </response>
    </productComputeSimplePrice>  
  </sdata:payload>
</entry>

At this point, the provider side MUST NOT delete the context in which the operation started because the consumer is allowed to GET the result more than once (and the semantics of a GET operation do not allow side-effects). The consumer is responsible for the clean-up. It MUST terminate the operation by sending a DELETE request on the operation URL:

DELETE http://www.example.com/myApp/myContract/-/products/$service/computeSimplePrice('abc42b0d-d110-4f5c-ac79-d3aa11bd20cb') 

At this point, the service provider MUST delete the context in which the operation started and return an OK status:

200 OK
The provider MAY choose to respond synchronously rather than asynchronously to an asynchronous request. In this case the provider will respond to the initial POST request with a 200 OK response if the request is successful. The calling logic on the consumer side MUST be set up to handle this case. If the initial POST returns a status different from 202, the caller MUST consider that the call has been processed synchronously and it should skip the asynchronous steps described above (GET to track progress and DELETE at the end).
SData providers and consumers MUST use the above protocol to invoke service operations asynchronously.

Previous Page Arrow Next Page Arrow