javascriptnode.jsexpressmernnode-cron

How to bypass clustering


I have an express server and i trying to schedule a job to send automatic emails at a particular time(10:00 am in my case). And i am using node-cron package to schedule jobs.

But i am making use of clustering technique to increase my app performance due to which there are multiple workers created and running constantly. In my implementation i am creating workers equal to total cpu of my machine because of which i have 8 workers running at all times.

To perform a job i have to schedule the job in my server.js, due to which my job i running 8 times at that particular time but i want it to run only once at that particular time.

Below is my server.js:

require("dotenv").config();
const express = require("express");
const { errorHandler } = require("./middleware/errorMiddleware");
const connectDB = require("./config/db");
const cors = require("cors");
const cluster = require("cluster");
const totalCPUs = require("os").cpus().length;
const process = require("process");
var cron = require('node-cron');
const port = process.env.PORT || 5000;

if (cluster.isMaster) {
  // console.log(`Number of CPUs is ${totalCPUs}`);
  // console.log(`Master ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < totalCPUs; i++) {
    cluster.fork();
  }

  // if any worker dies fork a new worker
  cluster.on("exit", (worker, code, signal) => {
    // console.log(`worker ${worker.process.pid} died`);
    // console.log("Let's fork another worker!");
    cluster.fork();
  });

} else {

  connectDB();
  
  const app = express();
  
  const corsOptions = {
    origin: 'http://localhost:3000',
    optionsSuccessStatus: 204
  };

  app.use(cors(corsOptions))
  app.use(express.json());
  app.use(express.urlencoded({ extended: false }));

  app.use("/api/admin", require("./routes/adminRoutes"));

  app.use(errorHandler);

 // This job run at 10:00 am every day
  cron.schedule('00 10 * * *', function() {
    console.log('send email');
  });
  
  app.listen(port, () => {
    console.log(`Running on ${port}`);
  });
}

For this implementation i get send email 8 times in my console.

And if i take out that schedule out of if else block and keep that schedule at the very end of server.js like shown below then i get send email 9 times in my console

// same code as above

app.use(errorHandler);

app.listen(port, () => {
    console.log(`Running on ${port}`);
  });
}

// This job run at 10:00 am every day
cron.schedule('00 10 * * *', function() {
    console.log('send email');
});

I tried few things but could not get the desired output. If there is any other way i can make use of then do tell me. Thanks in advance.


Solution

  • First off, cluster.isMaster has been deprecated since v16 so you should be using cluster.isPrimary instead.

    Then, you are putting the cron.schedule() code in the wrong place. You are putting it in the clustered processes when is should be inside the isPrimary block so that it is only run once.

    if (cluster.isPrimary) {
         cron.shedule(...); 
    }