DEV Community

Mayowa Ojo
Mayowa Ojo

Posted on

Prevent Your App From Idling on Heroku

This is a short article on how to stop your app from entering an idle/sleeping state when deployed to Heroku. If you have personal projects you hosted on Heroku servers which don't generate much traffic because they're just well, personal projects, you might have noticed it takes a considerable amount of time to serve up the page when you randomly go to the URL. This is because the free dynos provided by Heroku go to a sleeping mode when it doesn't receive any request for about 30 mins. However, if your app has more than one web dyno, it will never go into an idle state.

The dyno manager will reboot when a request is made but this takes roughly 10 seconds and that's why your site will seem slow. Read more about apps sleeping on Heroku in this post.

If for example, your app is a service that runs some scheduled background processes and doesn't necessarily make Http requests, then you don't want it going into sleep mode because your scheduled task won't run.

I'm going to cover two ways you can prevent idling in this post. Both methods are based on constantly making Http requests to your server in order to simulate the effect of traffic and keep the dyno busy.

- Using Timers

The first method is to use timers, notably the native setInterval function in NodeJS. Basically, the setInterval will call a function that makes a request continuously at a specified timer interval. Ideally, we'd like to keep that interval under 30 mins. Here's a code sample:

// keepAlive.js
const fetch = require('node-fetch');

// globals
const interval = 25*60*1000; // interval in milliseconds - {25mins x 60s x 1000}ms
const url = <some route exposed by your api>

(function wake() {

  try {

    const handler = setInterval(() => {

      fetch(url)
        .then(res => console.log(`response-ok: ${res.ok}, status: ${res.status}`)
        .catch(err => console.error(`Error occured: ${err}`));

    }, interval);

  } catch(err) {
      console.error('Error occured: retrying...);
      clearInterval(handler);
      return setTimeout(() => wake(), 10000);
  };

})();

We use an IIFE(immediately invoked function expression) since we want the timer to start once the server is up. Just import/require this file in your server/index.js file. We're also recursively calling the function should the request fail in order to try again after 10s.

- Using Cron Jobs

The second method, which is my preferred one uses a cron job. This is easier to work with and much cleaner in my opinion. A cron is simply a time-based job scheduler. Essentially, it will run a task given to it at a scheduled time continuously until it's stopped. There's a number of libraries to handle cron jobs and node-cron is one of them. Here's a code sample.

// keepAlive.js

const cron = require('cron');
const fetch = require('node-fetch');

// globals
const url = <some route exposed by your api>

(() => {


  const cronJob = cron.CronJob('0 */25 * * * *', () => {

    fetch(url)
      .then(res => console.log(`response-ok: ${res.ok}, status: ${res.status})
      .catch(err => );

  });

  cronJob.start();
})();

Here, we use an IIFE again to invoke the function. We create an instance of the CronJob class which takes the cron time as its first parameter and a callback. The cron time format means it will run every 25 minutes. A helpful tool to generate cron schedule expressions can be found here.

Now, since we don't need any particular response from the fetch method, we simply log the response status to the console and if you run $ heroku logs --tail in your terminal, you'd see these messages from the requests being made. You can use this to confirm that the requests are running constantly at the specified time interval.

Please share your thoughts below.

Top comments (2)

Collapse
 
manyfac3dg0d profile image
Vignesh Nandakumar

Not to be rude, there is one correction in cron code
const cronJob = cron.CronJob('0 */25 * * * *', () =>

should be
const cronJob = new cron.CronJob('0 */25 * * * *', () =>

Collapse
 
rbosamiya9 profile image
Ravindra Bosamiya

is it still working?? because I have read somewhere that in free tier heroku app sleeps for atleast 6 hours a day.