async findRecyclableLicense()

in functions/source/fgt-asg-handler/lib/aws/index.js [2731:2830]


    async findRecyclableLicense(stockRecords, usageRecords, limit = -1) {
        if (stockRecords instanceof Map && usageRecords instanceof Map) {
            let gracePeriod = (parseInt(this._settings['get-license-grace-period']) || 600) * 1000;
            // do health check on each item
            let queries = [],
                healthCheckResults,
                recyclableRecords = [],
                count = 0,
                maxCount,
                platform = this.platform;
            if (limit === 'all' || isNaN(limit) || parseInt(limit) <= 0) {
                maxCount = -1; // set a negative max count to indicate no limit
            } else {
                maxCount = parseInt(limit); // set a positive maxcount
            }
            usageRecords.forEach(item => {
                if (item.instanceId && item.scalingGroupName) {
                    queries.push(
                        (async function(rec) {
                            // get instance health check and instance info
                            let tasks = [];
                            tasks.push(
                                platform
                                    .getInstanceHealthCheck({
                                        instanceId: rec.instanceId,
                                        scalingGroupName: rec.scalingGroupName
                                    })
                                    .catch(() => null)
                            );
                            tasks.push(
                                platform
                                    .describeInstance({
                                        instanceId: item.instanceId,
                                        scalingGroupName: item.scalingGroupName,
                                        readCache: false
                                    })
                                    .catch(() => null)
                            );
                            let [healthCheck, instance] = await Promise.all(tasks);
                            return {
                                checksum: rec.checksum,
                                usageRecord: rec,
                                healthCheck: healthCheck,
                                instance: instance
                            };
                        })(item)
                    );
                }
            }, this);
            healthCheckResults = await Promise.all(queries);
            for (let result of healthCheckResults) {
                // recycle this stock record if checksum (of a license file) exists and the
                // corresponding instance which used this license doesn't exist or state isn't
                // in-sync
                // there's a situation when one fgt was assigned one license, the fgt need time
                // to get config, boot up, become available, and start to send hb.
                // until then the health check of that fgt won't be available. therefore, here
                // the script sets a grace period to allow for the fgt to become fully available.
                // if the fgt instance cannot come up and runniing by the grace period. it's
                // license will be recycled.
                // the health check here only verifies the in-sync state of any fgt instance but
                // it doesn't trigger failover.
                if (result.checksum && stockRecords.has(result.checksum)) {
                    let recyclable = false;
                    // if instance is gone? recycle the license
                    if (!result.instance) {
                        recyclable = true;
                    } else if (
                        result.instance &&
                        result.healthCheck &&
                        (!result.healthCheck.inSync ||
                            result.healthCheck.inevitableFailToSyncTime <
                                result.healthCheck.healthCheckTime)
                    ) {
                        // if instance exists but instance state isn't in-sync? recycle the license
                        recyclable = true;
                    } else if (
                        result.instance &&
                        !result.healthCheck &&
                        result.usageRecord &&
                        Date.now() > result.usageRecord.assignedTime + gracePeriod
                    ) {
                        // if instance exists but no healthcheck and grace period has passed?
                        recyclable = true;
                    }
                    // recycle the recyclable license
                    if (recyclable) {
                        count++;
                        if (maxCount < 0 || count <= maxCount) {
                            recyclableRecords.push(stockRecords.get(result.checksum));
                            if (count === maxCount) {
                                break;
                            }
                        }
                    }
                }
            }
            return recyclableRecords;
        }
    }