diff --git a/dev/bulkhead.js b/dev/bulkhead.js index ae1cbb542..9bb760c98 100644 --- a/dev/bulkhead.js +++ b/dev/bulkhead.js @@ -2,7 +2,7 @@ const _ = require("lodash"); const ServiceBroker = require("../src/service-broker"); -const E = require("../src/errors"); +const { randomInt } = require("../src/utils"); const broker = new ServiceBroker({ bulkhead: { @@ -31,7 +31,7 @@ broker.createService({ concurrency: 1 }, async handler(ctx) { - await this.Promise.delay(_.random(500, 2500)); + await this.Promise.delay(randomInt(500, 2500)); this.logger.info("First called.", ctx.params); @@ -45,7 +45,7 @@ broker.createService({ concurrency: 1 }, async handler(ctx) { - await this.Promise.delay(_.random(500, 2500)); + await this.Promise.delay(randomInt(500, 2500)); this.logger.info("Second called.", ctx.params); @@ -62,7 +62,7 @@ broker.createService({ }, async handler(ctx) { this.logger.info("Event received.", ctx.params); - await this.Promise.delay(_.random(500, 2500)); + await this.Promise.delay(randomInt(500, 2500)); this.logger.info("User created.", ctx.params); } }, @@ -70,7 +70,7 @@ broker.createService({ "post.created": { async handler(ctx) { this.logger.info("Event received.", ctx.params); - await this.Promise.delay(_.random(500, 2500)); + await this.Promise.delay(randomInt(500, 2500)); this.logger.info("Post created.", ctx.params); } } diff --git a/dev/client.js b/dev/client.js index a22f9a4ba..42e7e3f9c 100644 --- a/dev/client.js +++ b/dev/client.js @@ -3,10 +3,9 @@ const _ = require("lodash"); const kleur = require("kleur"); const fs = require("fs"); -const { MoleculerError, MoleculerRetryableError } = require("../src/errors"); -const Middlewares = require("..").Middlewares; const ServiceBroker = require("../src/service-broker"); +const { randomInt } = require("../src/utils"); // Create broker const broker = new ServiceBroker({ @@ -138,9 +137,8 @@ broker.createService({ actions: { add(ctx) { broker.logger.info(_.padEnd(`${ctx.params.count}. Add ${ctx.params.a} + ${ctx.params.b}`, 20), `(from: ${ctx.nodeID})`); - if (_.random(100) > 70) + if (randomInt(100) > 70) return this.Promise.reject(new MoleculerRetryableError("Random error!", 510)); - return { count: ctx.params.count, res: Number(ctx.params.a) + Number(ctx.params.b) @@ -173,7 +171,7 @@ broker pendingInfo = ` [${pendingReqs.join(",")}]`; } - const payload = { a: _.random(0, 10), b: _.random(0, 10) }; + const payload = { a: randomInt(0, 10), b: randomInt(0, 10) }; const count = ++reqCount; pendingReqs.push(count); let p = broker.call("math.add", payload, { meta: { count } }); diff --git a/dev/gossip-viz.js b/dev/gossip-viz.js index 5a26d951b..a550ab8a7 100644 --- a/dev/gossip-viz.js +++ b/dev/gossip-viz.js @@ -3,10 +3,11 @@ const _ = require("lodash"); const kleur = require("kleur"); const ServiceBroker = require("../src/service-broker"); +const { randomInt } = require("../src/utils"); const COUNT = process.argv[2] ? Number(process.argv[2]) : 20; const nodePrefix = process.argv[3] || "node"; -const namespace = "viz-" + Math.round(_.random(100)); +const namespace = "viz-" + randomInt(100); console.log(`Create ${COUNT} nodes...`); @@ -55,8 +56,8 @@ Promise.all(brokers.map(({ broker }) => broker.start())).then(() => { printStatuses(); }, 1000); - const timer = setInterval(() => { - const idx = _.random(brokers.length - 1); + setInterval(() => { + const idx = randomInt(brokers.length - 1); const { nodeID, broker } = brokers[idx]; if (broker) { diff --git a/dev/server.js b/dev/server.js index ada95fe4b..0ddd5c5bc 100644 --- a/dev/server.js +++ b/dev/server.js @@ -1,11 +1,9 @@ "use strict"; -const path = require("path"); const _ = require("lodash"); -const kleur = require("kleur"); const ServiceBroker = require("../src/service-broker"); -const { MoleculerError, MoleculerRetryableError } = require("../src/errors"); -const Middlewares = require("../src/middlewares"); +const { MoleculerRetryableError } = require("../src/errors"); +const { randomInt } = require("../src/utils"); // Create broker const broker = new ServiceBroker({ @@ -83,12 +81,11 @@ broker.createService({ //fallback: (ctx, err) => ({ count: ctx.params.count, res: 999, fake: true }), //fallback: "fakeResult", handler(ctx) { - const wait = _.random(500, 1500); this.logger.info( _.padEnd(`${ctx.meta.count}. Add ${ctx.params.a} + ${ctx.params.b}`, 20), `(from: ${ctx.nodeID})` ); - if (_.random(100) > 80) + if (randomInt(100) > 80) return this.Promise.reject( new MoleculerRetryableError("Random error!", 510, "RANDOM_ERROR") ); diff --git a/dev/sharding.js b/dev/sharding.js index cc18da354..3b8576b9a 100644 --- a/dev/sharding.js +++ b/dev/sharding.js @@ -1,5 +1,6 @@ -const ServiceBroker = require("../src/service-broker"); const _ = require("lodash"); +const ServiceBroker = require("../src/service-broker"); +const { randomInt } = require("../src/utils"); function createBroker(opts) { const broker = new ServiceBroker( @@ -39,7 +40,7 @@ function createBroker(opts) { }, handler(ctx) { //this.logger.warn(`Called '${this.broker.nodeID}' with '${ctx.params.name}'`); - return 20 + _.random(60); + return 20 + randomInt(60); } } } @@ -69,7 +70,7 @@ async function start() { const usernames = ["john", "bob", "adam", "steve", "mark"]; setInterval(async () => { - const name = usernames[_.random(usernames.length - 1)]; + const name = usernames[randomInt(usernames.length - 1)]; await main.call("users.getAge", { name }); }, 1000); } diff --git a/dev/tracing.js b/dev/tracing.js index 6a49c6034..c39eb027e 100644 --- a/dev/tracing.js +++ b/dev/tracing.js @@ -15,7 +15,7 @@ const ServiceBroker = require("../src/service-broker"); const { MoleculerError } = require("../src/errors"); const _ = require("lodash"); -const { inspect } = require("util"); +const { randomInt } = require("../src/utils"); const THROW_ERR = false; @@ -244,7 +244,7 @@ broker.createService({ }, async handler(ctx) { const span1 = ctx.startSpan("Fake delay"); - //await this.Promise.delay(10 + _.random(30)); + // await this.Promise.delay(10 + randomInt(30)); ctx.finishSpan(span1); return ctx.params.postID * 3; } @@ -265,7 +265,7 @@ broker.createService({ userID: ctx.params.userID }); - await this.Promise.delay(_.random(10)); + await this.Promise.delay(randomInt(10)); return ctx.params.userID * 3; } } @@ -280,7 +280,7 @@ broker.createService({ count: { tracing: true, async handler(ctx) { - //await this.Promise.delay(_.random(50)); + // await this.Promise.delay(randomInt(50)); return Math.round(Math.random() * 10); } } @@ -295,7 +295,7 @@ broker.createService({ count: { tracing: true, async handler(ctx) { - //await this.Promise.delay(_.random(50)); + // await this.Promise.delay(randomInt(50)); return Math.round(Math.random() * 10); } } diff --git a/examples/client-server/client.js b/examples/client-server/client.js index 7a8891210..0a8008f5e 100644 --- a/examples/client-server/client.js +++ b/examples/client-server/client.js @@ -6,6 +6,8 @@ let kleur = require("kleur"); let ServiceBroker = require("../../src/service-broker"); +const { randomInt } = require("../../src/utils"); + let transporter = process.env.TRANSPORTER || "TCP"; // Create broker @@ -81,7 +83,7 @@ broker pendingInfo = ` [${pendingReqs.join(",")}]`; } - let payload = { a: _.random(0, 100), b: _.random(0, 100), count: ++reqCount }; + let payload = { a: randomInt(0, 100), b: randomInt(0, 100), count: ++reqCount }; pendingReqs.push(reqCount); let p = broker.call("math.add", payload); if (p.ctx) { diff --git a/examples/client-server/server.js b/examples/client-server/server.js index f38f47791..f0600fb7c 100644 --- a/examples/client-server/server.js +++ b/examples/client-server/server.js @@ -1,10 +1,8 @@ "use strict"; let _ = require("lodash"); -let kleur = require("kleur"); let ServiceBroker = require("../../src/service-broker"); -let { MoleculerError } = require("../../src/errors"); let transporter = process.env.TRANSPORTER || "TCP"; @@ -23,7 +21,7 @@ broker.createService({ name: "math", actions: { add(ctx) { - // if (_.random(100) > 90) { + // if (randomInt(100) > 90) { // this.logger.info(kleur.bold.red("Throw random error...")); // throw new MoleculerError("Random error!", 510); // } diff --git a/examples/multi-nodes/node-controller.service.js b/examples/multi-nodes/node-controller.service.js index f480491f6..fea11ca63 100644 --- a/examples/multi-nodes/node-controller.service.js +++ b/examples/multi-nodes/node-controller.service.js @@ -3,7 +3,7 @@ const _ = require("lodash"); const kleur = require("kleur"); const cluster = require("cluster"); -const { humanize } = require("../../src/utils"); +const { humanize, randomInt } = require("../../src/utils"); const padS = _.padStart; const padE = _.padEnd; @@ -67,7 +67,7 @@ module.exports = { this.logger.info(`Stopping ${this.nodes.length - num} nodes...`); const tmp = Array.from(this.nodes); return _.times(this.nodes.length - num, () => { - const idx = _.random(tmp.length - 1); + const idx = randomInt(tmp.length - 1); const node = tmp.splice(idx, 1)[0]; if (opts.kill) return this.killNode(node); else return this.stopNode(node); diff --git a/examples/post.service.js b/examples/post.service.js index 8f9a7664a..3293b2aa7 100644 --- a/examples/post.service.js +++ b/examples/post.service.js @@ -3,13 +3,17 @@ let _ = require("lodash"); let fakerator = require("fakerator")(); +const { randomInt } = require("../src/utils"); + module.exports = function () { - let posts = fakerator.times(fakerator.entity.post, 10); + const posts = fakerator.times(fakerator.entity.post, 10); + + for (let i = 0; i < posts.length; i++) { + const post = posts[i]; - _.each(posts, (post, i) => { post.id = i + 1; - post.author = _.random(1, 5); - }); + post.author = randomInt(1, 5); + } return { name: "posts", diff --git a/src/registry/discoverers/etcd3.js b/src/registry/discoverers/etcd3.js index 5b5aaa16b..0c0b57eaf 100644 --- a/src/registry/discoverers/etcd3.js +++ b/src/registry/discoverers/etcd3.js @@ -11,7 +11,7 @@ const kleur = require("kleur"); const BaseDiscoverer = require("./base"); const { METRIC } = require("../../metrics"); const Serializers = require("../../serializers"); -const { removeFromArray } = require("../../utils"); +const { removeFromArray, randomInt } = require("../../utils"); const P = require("../../packets"); const C = require("../../constants"); @@ -43,7 +43,7 @@ class Etcd3Discoverer extends BaseDiscoverer { }); // Loop counter for full checks. Starts from a random value for better distribution - this.idx = this.opts.fullCheck > 1 ? _.random(this.opts.fullCheck - 1) : 0; + this.idx = this.opts.fullCheck > 1 ? randomInt(this.opts.fullCheck - 1) : 0; // Etcd client instance this.client = null; diff --git a/src/registry/discoverers/redis.js b/src/registry/discoverers/redis.js index 933506dc1..a057724f6 100644 --- a/src/registry/discoverers/redis.js +++ b/src/registry/discoverers/redis.js @@ -12,7 +12,7 @@ const { BrokerOptionsError } = require("../../errors"); const BaseDiscoverer = require("./base"); const { METRIC } = require("../../metrics"); const Serializers = require("../../serializers"); -const { removeFromArray, isFunction } = require("../../utils"); +const { removeFromArray, isFunction, randomInt } = require("../../utils"); const P = require("../../packets"); const C = require("../../constants"); @@ -43,7 +43,7 @@ class RedisDiscoverer extends BaseDiscoverer { }); // Loop counter for full checks. Starts from a random value for better distribution - this.idx = this.opts.fullCheck > 1 ? _.random(this.opts.fullCheck - 1) : 0; + this.idx = this.opts.fullCheck > 1 ? randomInt(this.opts.fullCheck - 1) : 0; // Redis client instance this.client = null; diff --git a/src/strategies/shard.js b/src/strategies/shard.js index 580d0bf53..bb0202363 100644 --- a/src/strategies/shard.js +++ b/src/strategies/shard.js @@ -10,7 +10,7 @@ const _ = require("lodash"); const BaseStrategy = require("./base"); const crypto = require("crypto"); const LRU = require("lru-cache"); -const { isFunction } = require("../utils"); +const { isFunction, randomInt } = require("../utils"); /** * Sharding invocation strategy @@ -67,7 +67,8 @@ class ShardStrategy extends BaseStrategy { * @memberof ShardStrategy */ select(list, ctx) { - let key = this.getKeyFromContext(ctx); + const key = this.getKeyFromContext(ctx); + if (key != null) { if (this.needRebuild) this.rebuild(list); @@ -76,7 +77,7 @@ class ShardStrategy extends BaseStrategy { } // Return a random item (no key) - return list[_.random(0, list.length - 1)]; + return list[randomInt(0, list.length - 1)]; } /** diff --git a/src/transporters/tcp/udp-broadcaster.js b/src/transporters/tcp/udp-broadcaster.js index b2fe1f4df..3601ede6c 100644 --- a/src/transporters/tcp/udp-broadcaster.js +++ b/src/transporters/tcp/udp-broadcaster.js @@ -10,7 +10,8 @@ const EventEmitter = require("events"); const os = require("os"); const dgram = require("dgram"); const ipaddr = require("ipaddr.js"); -const _ = require("lodash"); +const { randomInt } = require("../../../src/utils"); + /** * UDP Discovery Server for TcpTransporter * @@ -87,7 +88,7 @@ class UdpServer extends EventEmitter { }) .then(() => { // Send first discover message after ~1 sec - setTimeout(() => this.discover(), _.random(500) + 500); + setTimeout(() => this.discover(), randomInt(500) + 500); this.startDiscovering(); }); diff --git a/src/utils.js b/src/utils.js index 7f9f0ecf7..3f2c9b393 100644 --- a/src/utils.js +++ b/src/utils.js @@ -620,6 +620,34 @@ const utils = { .map(x => x.trim()) .filter(Boolean) : []; + }, + + /** + * Produces a random floating number between the inclusive lower and upper bounds. + * + * @param {Number} a + * @param {Number} b + * @returns {Number} + */ + random(a = 1, b = 0) { + const lower = Math.min(a, b); + const upper = Math.max(a, b); + + return lower + Math.random() * (upper - lower); + }, + + /** + * Produces a random integer number between the inclusive lower and upper bounds. + * + * @param {Number} a + * @param {Number} b + * @returns {Number} + */ + randomInt(a = 1, b = 0) { + const lower = Math.ceil(Math.min(a, b)); + const upper = Math.floor(Math.max(a, b)); + + return Math.floor(lower + Math.random() * (upper - lower + 1)); } }; diff --git a/test/services/posts.service.js b/test/services/posts.service.js index a4f8f6b7b..9b89249e6 100644 --- a/test/services/posts.service.js +++ b/test/services/posts.service.js @@ -1,15 +1,17 @@ const _ = require("lodash"); const fakerator = require("fakerator")(); -const { delay } = require("../../src/utils"); +const { delay, randomInt } = require("../../src/utils"); module.exports = function () { let posts = fakerator.times(fakerator.entity.post, 10); - _.each(posts, (post, i) => { + for (let i = 0; i < posts.length; i++) { + const post = posts[i]; + post.id = i + 1; - post.author = _.random(1, 5); - }); + post.author = randomInt(1, 5); + } return { name: "posts", diff --git a/test/unit/service-broker.spec.js b/test/unit/service-broker.spec.js index e77d42a6c..a51e041d1 100644 --- a/test/unit/service-broker.spec.js +++ b/test/unit/service-broker.spec.js @@ -47,7 +47,10 @@ jest.mock("../../src/utils", () => ({ functionArguments() { return ["ctx"]; }, - deprecate() {} + deprecate() {}, + randomInt() { + return 2; + } })); polyfillPromise = jest.requireActual("../../src/utils").polyfillPromise;