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`; if (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 }); } }