Data Throttling & Load Balancing


Terminology

Data throttling is processing data in limited chunks, as an intentional bottleneck added for predictable rate of processing / quantifiable throughput, to control resources consumption and/or a traffic quota.

Load balancing is enforcing a time quota on operations that need to take turns with other tasks in the system. As such, its implementation is usually limited to a single system, while data throttling can be employed by multiple systems independently.

Solution

With the help of method page, promises can be resolved in chunks, thus throttling the data processing, while method sequence can do the same on a one-by-one basis.

Both methods support return of promises from source or destination callbacks, which allows injecting any necessary delays needed to implement load balancing.

Examples

Balanced Page Source

The example below uses method page to initiate a sequence of 5 pages, and then logs the resolved data into the console. The source function serves each page with a half-second delay.

const spex = require('spex')(Promise);

function source(index, data, delay) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve([
                'page-' + index, // simple value;
                Promise.resolve(Date.now()) // promise value;
            ])
        }, 500); // wait 1/2 second before serving the next page;
    });
}

function logger(index, data, delay) {
    console.log('LOG:', data);
}

spex.page(source, {dest: logger, limit: 5})
    .then(data => {
        console.log('FINISHED:', data);
    });

Output:

LOG: [ 'page-0', 1446050705823 ]
LOG: [ 'page-1', 1446050706327 ]
LOG: [ 'page-2', 1446050706834 ]
LOG: [ 'page-3', 1446050707334 ]
LOG: [ 'page-4', 1446050707839 ]
FINISHED: { pages: 5, total: 10, duration: 2520 }
Balanced Sequence Receiver

In the following example we have a sequence that returns data while the index is less than 5, and the destination function that enforces a 1 second delay on processing each data resolved from the source.

const spex = require('spex')(Promise);

function source(index, data, delay) {
    console.log('SOURCE:', index, data, delay);
    if (index < 5) {
        return Promise.resolve(index);
    }
}

function dest(index, data, delay) {
    console.log('DEST:', index, data, delay);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve();
        }, 1000);
    });
}

spex.sequence(source, {dest: dest})
    .then(data => {
        console.log('DATA:', data);
    });

Output:

SOURCE: 0 undefined undefined
DEST: 0 0 undefined
SOURCE: 1 0 1011
DEST: 1 1 1001
SOURCE: 2 1 1001
DEST: 2 2 1001
SOURCE: 3 2 1000
DEST: 3 3 1000
SOURCE: 4 3 1001
DEST: 4 4 1001
SOURCE: 5 4 1000
DATA: { total: 5, duration: 5013 }