# 8 - Polling

In a regular RESTFUL API framework, and API call that does not return immediately (i.e. within 50ms - 500ms) is considered a big problem, as it jams up the server. An API call that takes minutes to complete will time out on the client.

However, it is completely reasonable that some transactions take a long time to complete. A financial transaction that calls a third party API will take as long as that backend API takes, which is especially a problem if the backend degrades under peak loads. Similarly, a KYC transaction may require manual intervention, so could take hours or days to complete.

To handle these cases, DATP specifically addresses long running transactions. Where possible an immediate reply will be sent to the client, but for longer running transactions DATP provides several options for getting the reply back to the client at a later time.

# Polling

With this approach, the client starts the transaction, and if it is not completed in the reply then the client waits a while and then periodically polls the server for the status of the transaction. It keeps doing this until the transaction is complete.

# Webhook reply

This is the "don't call us, we'll call you" approach. Rather than the client continually asking the server for the status of the transaction, it provides a URL that the server will call when there is a status change. We'll cover web hooks in a later tutorial.

# Polling Options

Polling involves two steps:

  1. The initial API call to start the transaction, and
  2. Repeat calls to get the transaction status.

The second group of calls only need to occur if the first call doesn't return a completed status, and only need to repeat until the transaction completes.

There are two types of polling calls. The first is a short poll, where the status is returned immediately. The second is a long poll, where the server waits for a while (usually eight seconds) with the hope that the transaction might complete within that time period.

# Fast response versus machine resources

Consider two cases:

A) We do a short poll, which returns immediately, then wait 8 seconds before trying again. This places less load on the server, because the server returns immediately. In the worst case the transaction completes slightly after the client polls, but the client won't know about it until it polls again eight seconds later. With a eight second polling interval, there will be an average delay of four seconds between when the transaction completes, and when the client gets the completion status.

B) We do a long poll, which takes eight seconds to return, and then we try again. This places more load on the server, as it needs to hold onto the res (response) object and watch for a transaction status change. The advantage however is that the server will return immediately if the transaction status changes, and the client gets to know almost immediately.

The choice of which polling strategy to use depends upon how long you expect the transaction to take to complete.

As a rule of thumb, if a transaction is expected to take only one, or a few polling attempts (e.g. less than 30 seconds) before the transaction completes, or if getting the reply is time-critical, then use long polling.

If a transaction is expected to take a while, and is not time critical, then use short polling. The longer the interval between short polls, the less the load on the server.

NOTE: Always include a delay between short poll requests. If you go into an un-restricted loop of calling the server, you will unecessarily overload the server, and in most frameworks will hit a rate limiter and be blocked.

C) If a transaction is expected to take an extended time to complete, use a web hook. This takes a little more effort to implement, but minimises load on both the client and the server, and ensures that the client gets the reply immediately. It is also resistant to client restarts, which might interupt a polling loop.

Option Time to run Description
A < 30 seconds long poll
B < a few minutes short poll
C long running web hook

# Demonstration - Long running transaction, with shortpoll

To view the different types of polling we can use MONDAT. Let's look at our long running myPipeline, which takes 30 seconds or more to complete. In the testing page, the default input specifies short polling...

{
  "metadata": {
    "reply": "shortpoll"
  },
  "data": {}
}
1
2
3
4
5
6

If we run this test while looking at both MONDAT and the server console, we see a few things:

  1. The response is immediate, with a status of "running".
  2. The polling commences, and the screen jumps to the Polling tab.
  3. There is a delay between when the transaction completes and when the result is displayed.

# Demonstration - Long running transaction, with longpoll

If we run myPipeline again, with the input changed to use "longpoll", we see slightly different behaviour:

  1. The initial response takes about eight seconds, but has the same status of "running".
  2. The polling then commences, and the screen jumps to the Polling tab.
  3. There is NOT a delay between when the transaction completes and when the result is displayed.

# Demonstration - Short running transaction, with shortpoll

The null transaction takes less than a second to complete. Test it in MONDAT using the default of shortpoll:

  1. The initial response returns immediately, with status "running". It does not wait to see that the transaction completes quickly. The bottom of the screen shows the time for the API call to complete (for example 19ms).
  2. The polling begins and returns pretty quickly with status "success".

# Demonstration - Short running transaction, with longpoll

Try the null transaction again, this time with longpoll:

  1. The initial response returns, with a status of "success".
  2. It takes longer than the previous shortpoll (e.g. 61ms) because it was waiting (and hoping) for the transaction to complete.
  3. There is no need for polling.

# Summary

From the above, we see that long polling gives a better "experience" to the client who is running the transaction. The client is promptly notified when the transaction is complete, and in some cases no polling is needed.

However...

Long polling places strain on the server, because it may have eight seconds or more of requests waiting for replies. If the server is experiencing thousands of requests a second this can be a big burden.

Whether you should use shortpoll and longpoll in client requests will depend upon the dynamics of your specific application. If performance and server load are a consideration, then ensure that clients only use longpolls for transactions that will return in a relatively short period of time.

Under no circumstances do you want thousands of clients long polling the server for hours on end, waiting for long running transactions to complete.

# Status URLs

The following URLs are used by a client to get the status of a transaction.

http://localhost:33370/datp/1.0/tx/status/<txId>        (defaults to shortpoll) http://localhost:33370/datp/1.0/tx/status/<txId>&reply=longpoll

In each of these, txId is the transaction ID returned in the initial API call that started the transaction.

{
  "metadata": {
    "owner": "acme",
    "txId": "tx-fc4106ac037e37da2fe3ba7f588d5f373ece7d6a", <=== HERE
    "externalId": null,
    "transactionType": "myPipeline",
    "status": "running",
    ...
  },
  "progressReport": null
}
1
2
3
4
5
6
7
8
9
10
11

Deployed on Github Pages.
Last updated: 2023-05-17, 15:37:23 UTC