Prevent Your App From Idling on Heroku
Tags: heroku, node
Published: 2020-03-03 23:29:33

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](https://blog.heroku.com/app_sleeping_on_heroku).

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:

```js
// 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.

```js
// 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](https://crontab.guru/).

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.