All files / src/drivers DefaultServiceBroker.ts

80.77% Statements 21/26
25% Branches 1/4
62.5% Functions 5/8
80.77% Lines 21/26

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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 1875x 5x 5x 5x 5x   5x 5x 5x         1x 1x     5x 5x   5x                                                                                                                                                                                                                                       1x           1x                                   5x       5x 5x   5x                   5x     5x            
const { defaultsDeep } = require("lodash"),
    os = require("os"),
    Moleculer = require("moleculer"),
    WinstonContext = require("winston-context"),
    { extend } = Moleculer.Logger;
 
import { RedisCacher } from "../utils/RedisCacher";
import { logger } from "../utils/Logger";
import { loadConfig } from "my-nconf";
 
let DEFAULT_BROKER_CONFIG;
class DefaultServiceBroker {
    constructor(config) {
        let c = defaultsDeep({}, config, DEFAULT_BROKER_CONFIG);
        return new Moleculer.ServiceBroker(c);
    }
}
export function CreateServiceBroker({ namespace, transporter, logger }) {
    let config = loadConfig();
 
    DEFAULT_BROKER_CONFIG = {
        namespace: namespace,
        nodeID: `${os.hostname()}:${process.pid}`,
 
        transporter: transporter,
 
        logger: logger,
        logLevel: "info", //has no effect rn.. since the logLevel from custom supplied logger takes precedent
        logFormatter: "default",
        logObjectPrinter: null,
        ///////////////////////
        // registry settings //
        ///////////////////////
        disableBalancer: false,
        registry: {
            preferLocal: true,
            strategy: "RoundRobin" // "Random"
            // strategy: "CpuUsage",
            // strategyOptions: {
            //     sampleCount: 3, //the number of samples.
            //     lowCpuUsage: 12 //the low CPU usage percent (%). The node which has lower CPU usage than this value is selected immediately.
            // }
            // strategy: "Latency",
            // strategyOptions: {
            //     sampleCount: 15,
            //     lowLatency: 20,
            //     collectCount: 10,
            //     pingInterval: 15
            // }
        },
        heartbeatInterval: 5,
        heartbeatTimeout: 15,
 
        //////////////////////////////////
        // Failures handling strategies //
        //////////////////////////////////
        maxCallLevel: 50, //prevent halting problems..
        trackContext: true, //enable gracefull shutdown
        gracefulStopTimeout: 5 * 1000, // waiting max 5 sec, This timeout can be overwrite in service settings with $gracefulStopTimeout property.
        requestTimeout: 12 * 1000,
        retryPolicy: {
            enabled: true,
            retries: 5,
            delay: 1000, //1 sec
            maxDelay: 5000,
            factor: 2, //exponential backoff
            check: err => !!err.retryable
        },
        circuitBreaker: {
            enabled: true,
            threshold: 0.5,
            minRequestCount: 20,
            windowTime: 60, // in seconds
            halfOpenTime: 12 * 1000,
            check: err => err && err.code >= 500
        },
        /////////////
        // Transit //
        /////////////
        transit: {
            maxQueueSize: 50 * 1000,
            packetLogFilter: ["HEARTBEAT"], //dont log out these packages
            disableReconnect: false
        },
 
        tracking: {
            enabled: true,
            shutdownTimeout: 5000
        },
        //////////////////////////////
        // Services lvl settings    //
        //////////////////////////////
        cacher: _getCacher(namespace, config),
 
        serializer: null, //default 2 JSONSerializer
        validation: true, //validate params before calling handlers
        validator: null, //use default
 
        metrics: true, //measure metrics on actions calls
        metricsRate: 1, //measaure metrics for 100% calls, 0.8 => 80%
        statistics: true, // get node info call $node.stat
 
        internalServices: true, //enable internal $node. call
 
        hotReload: false, //use other tools instead (gulp, nodemon, etc), this "built-in" feature suckkkkk
 
        ServiceFactory: null,
        ContextFactory: null,
 
        // Add middlewares
        middlewares: [
            // (handler, action) => {
            //     return function cacherMiddleware(ctx) {
            //         const cacheKey = this.getCacheKey(
            //             action.name,
            //             ctx.params,
            //             action.cache.keys
            //         );
            //         const content = this.get(cacheKey);
            //         if (content != null) {
            //             // Found in the cache! Don't call handler, return with the cached content
            //             ctx.cachedResult = true;
            //             return Promise.resolve(content);
            //         }
            //         // Call the handler
            //         return handler(ctx).then(result => {
            //             // Afterwards save the response to the cache
            //             this.set(cacheKey, result);
            //             return result;
            //         });
            //     }.bind(this);
            // }
        ],
 
        // Fired when the broker created
        created(broker) {
            return broker.logger.info(`Created broker ${broker.nodeID}`);
        },
 
        // Fired when the broker started
        started(broker) {
            // You can return Promise
            return broker.logger.info(
                `Broker ${broker.nodeID} joined \`${
                    broker.namespace
                }\` namespace`
            );
        },
 
        // Fired when the broker stopped
        stopped(broker) {
            // You can return Promise
            return broker.logger.info(
                `Broker ${broker.nodeID} left \`${broker.namespace}\` namespace`
            );
        },
 
        replCommand: []
    };
 
    return DefaultServiceBroker;
}
 
function _getCacher(namespace, config) {
    let ttl = 3600,
        prefix = `${namespace.toUpperCase()}-Cache`;
 
    Iif (config.has("redis_cache_cluster")) {
        logger.debug(
            "Redis Cache Cluster config options found. Using Redis Cache."
        );
        return new RedisCacher({
            ttl,
            prefix,
            redis_cluster: config.get("redis_cache_cluster")
        });
    } else {
        logger.debug(
            "Redis Cache Cluster config options not found. Using Memory Cache."
        );
        return new Moleculer.Cachers.Memory({
            ttl,
            prefix
        });
    }
}