All files / node-activedirectory/lib/services/internal service.maxPromisesAtOnce.js

0% Statements 0/62
0% Branches 0/27
0% Functions 0/16
0% Lines 0/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144                                                                                                                                                                                                                                                                                               
// this module will give you the possibility to make add alot of promises, but it will make sure, that only a fixed number is open.
// It was initially created to limit the number of promises making a tcp request (as windows only allows 5000 at once by default)
 
// If you provide a key you can make sure that you limit all the operations of a similar type. For example name your Type 'TCP' and all the functons
// calling with that key will use the same launch array. So if F1 calls it with 5000 Promises and F2 calls it with 5000 Promises the total limit will
// still be intact and not doubled
 
let currentPromiseArrays = {};
let currentPromiseMaxNumbers = {};
 
/**
 * Returns an Array of Objects that are used in the PromisesWithMaxAtOnce Function.
 *
 * @public
 * @param {Function} PromiseFunc Function that returns a Promise with one InputParameter that is used
 * @param {Array} InputValues Array with the Inputvalues. One promise for each entry is created
 * @param {Number} StartingIndex Every entry will have an index to later determin which promise of the array was resolved
 */
 
const getLaunchArray = (PromiseFunc, InputValues, StartingIndex) => {
    // This function will return a launch Array. It takes a function that returns a promise and it's input Values as an array
    // The output is an array with each entry having 3 elements
    // resolveLaunchPromise is the function that resolves tha launchPromise with the same index
    // launchPromise triggers the execution of promisewithTcpRequest
    // promiseFunc The Input Promise with the correlating Inputvalue
 
 
    let startingIndex = StartingIndex ? StartingIndex : 0;
    let launchArray = InputValues.map(function(InputValue, Index) {
        let obj = {};
        let resLPromise;
        // Expose the resolve of the promise, so it can be called from outsite
        obj.launchPromise = new Promise((resolve, reject) => {
            resLPromise = resolve;
        });
        // Add some logic to the resolvePromise
        obj.resolveLaunchPromise = () => {
            obj.isRunning = true;
            resLPromise();            
        }
 
        obj.isRunning = false;
        obj.isRejected = false;
        obj.isResolved = false;
        obj.index = startingIndex + Index;
 
        obj.promiseFunc = new Promise((resolve, reject) => {
            obj.launchPromise.then(() => {
                PromiseFunc(InputValue).then((data) =>{
                    obj.isRunning = false;
                    obj.isResolved = true;
                    resolve(data);
                }, (err) => {
                    obj.isRunning = false;
                    obj.isRejected = true;
                    reject(err)
                });
            });
        });
        return obj;
    });
 
    return launchArray;    
}
 
/**
 * For the specified group, retrieve all of the users that belong to the group.
 *
 * @public
 * @param {Function} PromiseFunc Function that returns a Promise with one InputParameter that is used
 * @param {Array} InputValues Array with the Inputvalues. One promise for each entry is created
 * @param {Number} MaxAtOnce Number of Promises that can run at the same time
 * @param {String} TypeKey A Key that is set to group promises together. So e.g. you set the key to TCP no matter which function calls with that Key it wont exceed the maxAtOnce Promises 
 */
 
const PromisesWithMaxAtOnce = (PromiseFunc, InputValues, MaxAtOnce, TypeKey) => {
    // You can input any promise that should be limited by open at the same time
    // PromiseFunc is a function that returns a promise and takes in an input value
    // InputValue is an Array of those InputValues
    // MaxAtOnce is the number of Promises maximum pending at the same time
 
    if(TypeKey){
        currentPromiseArrays[TypeKey] = currentPromiseArrays[TypeKey] || [];
        MaxAtOnce = currentPromiseMaxNumbers[TypeKey] ? currentPromiseMaxNumbers[TypeKey] : MaxAtOnce;
        
        if(!currentPromiseMaxNumbers[TypeKey]) currentPromiseMaxNumbers[TypeKey] = MaxAtOnce;
 
    }
    let alreadyRunning = TypeKey ? (currentPromiseArrays[TypeKey] ): [];
    let runningPromises = getCountRunningPromises(alreadyRunning);      
    let launchArray = getLaunchArray(PromiseFunc, InputValues, alreadyRunning.length);    
 
    alreadyRunning = alreadyRunning.concat(launchArray);
    // Launch idex is the current index of the promise in the array that is beeing started; 
    let launchIndex = getCountFinishedOrRunningPromises(alreadyRunning);
 
    // First start as much promises as are allowed at once (if there are less in the array than max allowed, start all of them)
    for(let i=launchIndex; runningPromises < MaxAtOnce && i < alreadyRunning.length; i++){
        alreadyRunning[i].resolveLaunchPromise();
        runningPromises = getCountRunningPromises(alreadyRunning);
        launchIndex = getCountFinishedOrRunningPromises(alreadyRunning);
    }
 
    // For each Promise that finishes start a new one until all are launched
    alreadyRunning.map((Value, Index) => {
        // Only map for indices bigger than the current launch index as everything smaller has already been launched;
        if(Index >= launchIndex -1  && launchIndex < alreadyRunning.length){
            Value.promiseFunc.then(() => {
                if(launchIndex < alreadyRunning.length){
                    alreadyRunning[launchIndex].resolveLaunchPromise();
                }
                runningPromises = getCountRunningPromises(alreadyRunning);
                launchIndex = getCountFinishedOrRunningPromises(alreadyRunning);
                        
            }, err => {
                console.log("ERROR IN SERVICE.MAXPROMISESATONCE");
                console.log(err);
                if(launchIndex<alreadyRunning.length){
                    alreadyRunning[runningPromises].resolveLaunchPromise();
                } 
                runningPromises = getCountRunningPromises(alreadyRunning);
                launchIndex = getCountFinishedOrRunningPromises(alreadyRunning);
            });
        }        
    });
 
    if(TypeKey){
        currentPromiseArrays[TypeKey] = alreadyRunning;
    }
    return launchArray;
}
 
function getCountRunningPromises(PromiseArray){
    // 
    return PromiseArray.filter(Entry => {return Entry.isRunning === true}).length;
}
 
function getCountFinishedOrRunningPromises(PromiseArray){
    return PromiseArray.filter(Entry => {return Entry.isRunning || Entry.isResolved || Entry.isRejected}).length;
}
 
 
 
module.exports = PromisesWithMaxAtOnce;