From 15936d63b89e0c715fdfe4e46b4a633a9982e1dc Mon Sep 17 00:00:00 2001 From: baalmart Date: Sat, 4 Nov 2023 11:50:11 +0300 Subject: [PATCH 1/2] scheduling daily SIM status checks --- src/incentives/bin/cronJob.js | 65 ++++++++++++++++++++++++++++++++ src/incentives/package-lock.json | 35 +++++++++++++++++ src/incentives/package.json | 1 + 3 files changed, 101 insertions(+) create mode 100644 src/incentives/bin/cronJob.js diff --git a/src/incentives/bin/cronJob.js b/src/incentives/bin/cronJob.js new file mode 100644 index 0000000000..89d7156b1d --- /dev/null +++ b/src/incentives/bin/cronJob.js @@ -0,0 +1,65 @@ +const cron = require("node-cron"); +const UserModel = require("@models/User"); +const constants = require("@config/constants"); +const inactiveThreshold = constants.INACTIVE_THRESHOLD || 2592000000; // 30 days +const log4js = require("log4js"); +const logger = log4js.getLogger( + `${constants.ENVIRONMENT} -- bin/cronJob script` +); + +// Everyday at midnight +cron.schedule("0 0 * * *", async () => { + try { + const batchSize = 100; // Process 100 users at a time + let skip = 0; + + while (true) { + const users = await UserModel("airqo") + .find({ + $or: [ + { + lastLogin: { + $lt: new Date(Date.now() - inactiveThreshold), + }, + }, + { + lastLogin: null, + }, + ], + isActive: { $ne: false }, // Exclude users where isActive is false + }) + .limit(batchSize) + .skip(skip) + .select("_id") + .lean(); + + if (users.length === 0) { + break; + } + + const userIds = users.map((user) => user._id); + + // Process the users with a delay between each batch + await processUsersWithDelay(userIds); + + skip += batchSize; + } + } catch (error) { + logger.error( + `An error occurred in the cron job --- ${JSON.stringify(error)}` + ); + } +}); + +async function processUsersWithDelay(userIds) { + const delay = 5000; // 5 seconds delay between requests + for (const userId of userIds) { + await updateUserAndDelay(userId, delay); + } +} + +async function updateUserAndDelay(userId, delay) { + await UserModel("airqo").updateMany({ _id: userId }, { isActive: false }); + + return new Promise((resolve) => setTimeout(resolve, delay)); +} diff --git a/src/incentives/package-lock.json b/src/incentives/package-lock.json index 53276b6267..1a05daf3f7 100644 --- a/src/incentives/package-lock.json +++ b/src/incentives/package-lock.json @@ -35,6 +35,7 @@ "mongoose-unique-validator": "^2.0.3", "morgan": "~1.9.0", "mtn-momo": "^2.0.0", + "node-cron": "^3.0.2", "node-fetch": "^2.6.1", "node-schedule": "^2.1.1", "nodemailer": "^6.9.4", @@ -5868,6 +5869,25 @@ "node": ">=4.0.0" } }, + "node_modules/node-cron": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", + "integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==", + "dependencies": { + "uuid": "8.3.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/node-cron/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -13209,6 +13229,21 @@ "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==" }, + "node-cron": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", + "integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==", + "requires": { + "uuid": "8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, "node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", diff --git a/src/incentives/package.json b/src/incentives/package.json index d1b87fcd22..4a09aad1e8 100644 --- a/src/incentives/package.json +++ b/src/incentives/package.json @@ -54,6 +54,7 @@ "mongoose-unique-validator": "^2.0.3", "morgan": "~1.9.0", "mtn-momo": "^2.0.0", + "node-cron": "^3.0.2", "node-fetch": "^2.6.1", "node-schedule": "^2.1.1", "nodemailer": "^6.9.4", From db58dec574bf6b02b502ca0dcb1c236921e89677 Mon Sep 17 00:00:00 2001 From: baalmart Date: Mon, 6 Nov 2023 02:55:07 +0300 Subject: [PATCH 2/2] cronjob for checking the status of the sim card --- src/incentives/bin/cronJob.js | 65 ++++++++++++++++------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/src/incentives/bin/cronJob.js b/src/incentives/bin/cronJob.js index 89d7156b1d..5e54881746 100644 --- a/src/incentives/bin/cronJob.js +++ b/src/incentives/bin/cronJob.js @@ -1,46 +1,30 @@ const cron = require("node-cron"); -const UserModel = require("@models/User"); +const SimModel = require("@models/Sim"); const constants = require("@config/constants"); -const inactiveThreshold = constants.INACTIVE_THRESHOLD || 2592000000; // 30 days const log4js = require("log4js"); const logger = log4js.getLogger( `${constants.ENVIRONMENT} -- bin/cronJob script` ); +const checkStatus = require("@utils/create-sim").checkStatus; +const secondsDelayBetweenRequests = 20000; +const internetDataBalanceThreshold = 5; // Everyday at midnight cron.schedule("0 0 * * *", async () => { try { - const batchSize = 100; // Process 100 users at a time + const batchSize = 100; // Process 100 SIM cards at a time let skip = 0; + const simCards = await SimModel("airqo").find({}).select("_id").lean(); + while (true) { - const users = await UserModel("airqo") - .find({ - $or: [ - { - lastLogin: { - $lt: new Date(Date.now() - inactiveThreshold), - }, - }, - { - lastLogin: null, - }, - ], - isActive: { $ne: false }, // Exclude users where isActive is false - }) - .limit(batchSize) - .skip(skip) - .select("_id") - .lean(); + const simBatch = simCards.slice(skip, skip + batchSize); - if (users.length === 0) { + if (simBatch.length === 0) { break; } - const userIds = users.map((user) => user._id); - - // Process the users with a delay between each batch - await processUsersWithDelay(userIds); + await processSimCardsWithDelay(simBatch); skip += batchSize; } @@ -51,15 +35,24 @@ cron.schedule("0 0 * * *", async () => { } }); -async function processUsersWithDelay(userIds) { - const delay = 5000; // 5 seconds delay between requests - for (const userId of userIds) { - await updateUserAndDelay(userId, delay); +async function processSimCardsWithDelay(simBatch) { + for (const sim of simBatch) { + const responseFromCheckStatus = await checkStatus({ + query: { tenant: "airqo" }, + params: { sim_id: sim._id }, + }); + + // Check if data.balance is less than the declared threshold and log it + if ( + responseFromCheckStatus.success && + responseFromCheckStatus.data.balance < internetDataBalanceThreshold + ) { + logger.info( + `SIM card ${sim._id} has a balance less than ${internetDataBalanceThreshold}` + ); + } + await new Promise((resolve) => + setTimeout(resolve, secondsDelayBetweenRequests) + ); } } - -async function updateUserAndDelay(userId, delay) { - await UserModel("airqo").updateMany({ _id: userId }, { isActive: false }); - - return new Promise((resolve) => setTimeout(resolve, delay)); -}