Skip to content

why-jay/scheduled-throttle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

#Scheduled Throttle

A throttled function will only execute once until it passes a certain time of day (backed by Redis).

##Install

npm install scheduled-throttle

##Example

Check out the following example written in ES6. Hopefully you're familiar with coroutines/generators/Bluebird! :)

var REDIS_KEYS_EXPIRE = 1000000;

var scheduledThrottle = require('scheduled-throttle');
var assert = require('assert');
var Bluebird = require('bluebird');

var throttler = scheduledThrottle.create({
    client: redisClient, // required
    key: 'foo:1', // required - Redis key name
    timezone: '+0900', // required
    localChangeTimes: [ // required
        '0400',
        '1430'
    ],
    inactivityExpire: REDIS_KEYS_EXPIRE, // optional - in seconds
                                 // if not set, the relevant Redis keys never expire
    serialize: function (numberResult) { // optional
        // If not set, a default serializer is used (which is basically a JSON.stringify()
        // that can handle undefined). Redis can only store strings, so everything needs
        // to be converted to and from a string.
        return String(numberResult);
    },
    deserialize: function (stringStored) { // optional - similar to the serialize
        // If not set, a default deserializer is used (which is basically a JSON.parse()
        // that can handle undefined)
        return JSON.parse(stringStored);
    }
}));
throttler = Bluebird.promisifyAll(throttler);

var obj = {
    a: 2,
    throttledFn: throttler.throttle(function (x, cb) { // callback should be a nodeback
        console.log('executed');
        cb(null, x + this.a);
    })
};
obj = Bluebird.promisifyAll(obj);

Bluebird.coroutine(function* () {
    yield throttler.clearAsync(); // "clear" method - clears out all relevant Redis keys
    
    var result = yield obj.throttledFnAsync(1);
    // 'executed' is printed because of console.log() above
    assert.strictEqual(result, 1 + 2);
    
    var will = yield throttler.willExecuteAsync();
    // will not execute until either 04:00 or 14:30 (local time)
    assert.strictEqual(result, false);
    // also, after REDIS_KEYS_EXPIRE seconds,
    // relevant Redis keys will be cleared out, as if throttler.clear() is called

    var result2 = yield obj.throttledFnAsync(1);
    assert.strictEqual(result2, scheduledThrottle.THROTTLED);     
})();

Now check out the "preserveResult" option:

var throttler = Bluebird.promisifyAll(scheduledThrottle.create({
    client: redisClient,
    key: TEST_KEY_NAME,
    timezone: '+0900',
    localChangeTimes: ['0400'],
    preserveResult: true /*** NOTICE THIS OPTION! ***/
}));

var c = {u: 1, v: '1'};
var throttledFn = throttler.throttle(function (cb) { cb(null, c); });
var throttledFnAsync = Bluebird.promisify(throttledFn);

Bluebird.coroutine(function* () {
    var result = yield throttledFnAsync();
    assert.strictEqual(result, c);
    
    var result2 = yield throttledFnAsync();
    assert.deepEqual(result2, c); // previous result has been kept along and is returned
    assert.notStrictEqual(result2, scheduledThrottle.THROTTLED); // instead of THROTTLED
})();

##Error within the function being throttled

When there is an error (not necessarily an Error object) is thrown inside the function being throttled, the throttler will stop the process immediately and no changes will occur with Redis.

const throttledFnAsync = Bluebird.promisify(throttler2.throttle(cb => cb(new Error('intentional'))));
try {
    yield throttledFnAsync();
} catch (err) {
    assert.strictEqual(err.message, 'intentional');
    try {
        yield throttledFnAsync(); // should throw again
    } catch (err) {
        assert.strictEqual(err.message, 'intentional');
    }
}

##Pretending a Time of Day

For testing purposes, you may want to pretend it's a certain time of day right now. In such cases, simply pass a Date object as the first argument of .throttle() or .willExecute():

var throttler = scheduledThrottle.create({
    (other options...),
    timezone: '+0900',
    localChangeTimes: ['0400']
}));

var simulatedThrottledFn = throttler.throttle(new Date('2013-03-01T04:01:00+0900'), function (cb) {
    // will simulate as if it is 04:01 right now
});

##Test

Test is written in ES6, so 6to5 is used for transpilation.

npm install
npm test

About

Function will only execute once until it passes a certain time of day (backed by Redis).

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published