57

There is literally no tutorial about using Heroku Scheduler with Node.js. Assume that I have a function called sayHello() and I would like to run it every 10 mins. How can I use it in controller. In ruby you write rake function_name() however no explanation made for Node. Can I write '/sayHello' or I should do extra configuration?

Ali
  • 5,338
  • 12
  • 55
  • 78

6 Answers6

93

Create the file <project_root>/bin/say_hello:

#! /app/.heroku/node/bin/node
function sayHello() {
    console.log('Hello');
}
sayHello();
process.exit();

Deploy to Heroku and test it with $ heroku run say_hello then add it to the scheduler with task name say_hello.

Explanation

Take say_hello.js as an example of a Node.js script that you would normally run using $ node say_hello.js.

Turn it into a script by

  1. removing the .js ending
  2. inserting the 'shebang' at the top: #! /app/bin/node [1][2]
  3. moving it into the bin directory [3]

[1] Read about the shebang on Wikipedia.
[2] The node executable is installed in app/bin/node on Heroku. You can check it out by logging into bash on Heroku with $ heroku run bash then asking $ which node.
[3] Heroku requires scripts to be placed in the bin directory. See Defining Tasks in the Heroku Dev Center.

I agree that the Heroku documentation for scheduling tasks is not very clear for anything other than Ruby scripts. I managed to work it out after some trial and error.

starball
  • 20,030
  • 7
  • 43
  • 238
Philip Poots
  • 954
  • 7
  • 4
  • 2
    Great answer! What is the exit() method (I tried this example and received a method not defined error)? – Buu Jan 24 '13 at 17:57
  • To clarify, must the script be in the bin directory in the root of the project repo, or the bin of the dyno its self? I can see /bin/ when I do heroku run bash, but I can't deploy code there from git... Thanks! – Zeke Nierenberg Jun 20 '13 at 15:16
  • @dancrews http://www.nczonline.net/blog/2014/02/04/maintainable-node-js-javascript-avoid-process-exit/ – jpotts18 Jun 18 '14 at 19:42
  • I found that using a bash script with the shebang did not allow me to use `var script = require('../path/to/script');`. I switched to [Christophe's answer](http://stackoverflow.com/a/16378771/517712) and it was a better solution for me. – brettjonesdev Dec 27 '14 at 21:06
  • 5
    asking `$ which node` in heroku bash gave me `/app/.heroku/node/bin/node` as a path for node in my case. Which I entered instead of app/bin/node, and it works perfectly. Thanks for the detailed walkthrough and note [2] in particular. – RaphKomjat Jan 23 '16 at 22:59
  • 4
    I used `#!/usr/bin/env node` instead of `#! /app/bin/node`. – jengeb Apr 20 '16 at 16:16
  • very good explained. I used different default shebang /app/.heroku/node/bin/node – Rober Jun 21 '16 at 18:06
  • `process.exit();` immediatley after `sayHello` for example resulted in my script not finishing and only once removed did it run fully and complete? Thanks. – Michael Jun 07 '20 at 10:45
44

A better approach is to define your schedule file called for example worker.js with following content:

function sayHello() {
    console.log('Hello');
}
sayHello();

and then in the heroku schedule, you just write node worker like you define it in the Procfile and that's all!

Matthias Herlitzius
  • 3,365
  • 2
  • 20
  • 20
Christophe Vidal
  • 1,894
  • 1
  • 19
  • 13
28

Christophe's answer worked for me until I needed to pass a parameter to the script, at which point it failed. The issue is that node should not be specified in the task. Here is how exactly to get it working:

  1. In your Procfile, define a process type for your script. See below for a typical Procfile with a web process and, for running "scheduled_job.js", a second process type imaginatively named "worker".

    web: node app.js
    worker: node scheduled_job.js
    
  2. In the Heroku scheduler's Task column, just enter the name of the process type ("worker" in this example) with or without parameters. Don't enter 'node' before it. Heroku shows a dollar sign in front of it, so examples of a valid setup would be $ worker (run without arguments) or $ worker 123 abc (to execute scheduled_job.js with arguments "123" and "abc")

Clafou
  • 15,250
  • 7
  • 58
  • 89
7

I am confused that nobody tried:

$ heroku run node yourScript.js

So put this in Heroku Scheduler

node yourScript.js

Worked for me.

PS: be sure to import everything your script needs.

Simon Franzen
  • 2,628
  • 25
  • 34
5

Following steps work in my situation.

  1. In the root folder add worker.js file.
  2. In worker.js. Write an simple function, like above. function sayHello() { console.log('Hello'); } sayHello();
  3. Go to heroku Scheduler add-ons. Click 'add new job' and type 'worker' in the field. Then set time interval and click save.

Here are something should notice

  1. After update works setting.If using above example, you can use heroku run node worker.js to check if it work. It should be show 'Hello' in your terminal.
  2. I use express-babel starter for my node.js project.
陳見綸
  • 51
  • 1
  • 3
1

Thnks so much for the previous answers here.

I found the following worked for me where feed.js is the script to run as a job on Heroku.:

<PROJECT_ROOT>/bin/feed.js

The contents of feed.js start with:

#!/usr/bin/env node

async function mediumFeed() {

  await fetch('https://medium.com/feed/stokedinfluence')

And end with:

}

mediumFeed();

And on Heroku the job is defined as node bin/medium_feed.js:

enter image description here

enter image description here

To run the node js script locally feed.js you can use from the root of your project directory node bin/feed.js and to run via heroku you can use heroku run feed.js --app <APP_NAME_NOT_PIPELINE_NAME>. When using heroku command, this will run the job from the server where as running node bin/feed.js will run locally. Run locally to test and verify the code works, once deployed verify it works with the heroku run... command

Michael
  • 591
  • 8
  • 24