Using Heroku Scheduler with Node.js - node.js

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?

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
removing the .js ending
inserting the 'shebang' at the top: #! /app/bin/node [1][2]
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.

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!

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:
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
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")

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.

Following steps work in my situation.
In the root folder add worker.js file.
In worker.js. Write an simple function, like above.
function sayHello() {
console.log('Hello');
}
sayHello();
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
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.
I use express-babel starter for my node.js project.

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:
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

Related

Jenkins: Replace running Express-app with the most current Express-app

I have created a Jenkins-file, which first pulls the sources of a Express-app from the GitHub-Repository, then installs the dependencies, then starts the Express-App.
pipeline {
agent any
tools {
nodejs 'NodeJS'
}
stages {
stage('Build') {
steps {
sh 'npm install'
echo "install dependencies."
}
}
stage('Deploying') {
steps {
sh 'node index.js'
echo "run express-app ..."
}
}
}
}
Now I have configured "Scan Repository Triggers" to 15 minutes. So, that Jenkins runs the Jenkins-file every 15 minutes, in case there have been changes in the GitHub-repository.
The problem is, that the previous app is still running and occupying the port, which is defined in the sources.
How can I stop the older, running app and replace it with the updated app? The target is, that the respective most current version of the app is supplied, if one enters the URL.
There are multiple ways to get this done. One way is to use something like nodemon. Another clean way to manage our node server is by using something like forever. Then you can Gracefully manage the server.
forever start app.js
forever restart app.js
If you don't want to rely on additional tools. You can kill the Node server before starting it again. There are multiple ways to do this. One option is to get the process ID by the port and then kill the server. You can refer to this question.

child_process.fork not starting an express server inside of packaged electron app

I have an electron app where I need not only to run the interface to the user but also start an express server that will serve files for people connected through the network.
I have everything working if I start both electron and the express server normally, but I'm pretty confident that I will need the server running in a different thread to avoid slugish interface and even problems with the server.
For that matter I tried to run my express server using the child_process.fork and it worked when I use npm start, but when I use electron-builder to create an .exe, the installed program doesn't start the express server.
I tried to run my server right away using:
require('child_process').fork('app/server/mainServer.js')
I tried several changes, prefixing the file with __dirname, process.resourcesPath and even hard coding the generated file path; changing the fork options to pass cwd: __dirname, detached: true and stdio: 'ignore'; and even tried using spawn with process.execPath, which will also work with npm start but won't when packaged (it keeps opening new instances of my app, seems obvious after you do hehe)
Note: If I don't fork and require the server script right away, using require('server/mainServer.js') it works on the packaged app, so the problem most like isn't the express itself.
Note 2: I have asar: false to solve other problems, so this is not the problem solver here.
I put up a small git project to show my problem:
https://github.com/victorivens05/electron-fork-error
Any help will be highly appreciated.
With the great help from Samuel Attard (https://github.com/MarshallOfSound) I was able to solve the problem (he solved for me actually)
As he said:
the default electron app will launch the first file path provided to it
so `electron path/to/thing` will work
in a packaged state, that launch logic is not present
it will always run the app you have packaged regardless of the CLI args passed to it
you need to handle the argument manually yourself
and launch that JS file if it's passed in as the 1st argument
The first argument to fork simply calls `process.execPath` with the first
argument being the path provided afaik
The issue is that when packaged Electron apps don't automatically run the
path provided to them
they run the app that is packaged within them
In other words. fork is actually spawn being executed with process.execPath and passing the fork's first argument as the second for spawn.
What happens in a packaged app is that the process.execPath isn't electron but the packaged app itself. So if you try to spawn, the app will be open over and over again.
So, what Samuel suggest was implemented like this:
if (process.argv[1] === '--start-server') {
require('./server/mainServer.js')
return
}
require('./local/mainLocal.js')
require('child_process').spawn(process.execPath, ['--start-server'])
That way, the first time the packaged app will be executed, the process.argv[1] will be empty, so the server won't start. It will then execute the electron part (mainLocal in my case) and start the app over, but this time passing the argv. Next time the app starts, it will start the server and stop the execution, so the app won't open again because spawn is never reached.
Huge thanks to Samuel.

How can I run grunt as a daemon?

I am running a packaged nodejs webserver that allows for reading of epub files (Readium-JS), and it is started with the grunt command.
However, if I run this on my VPS the server dies as soon as my terminal connection ends.
How can I run this task as a daemon?
I have looked at options like grunt-forever and grunt-daemon but the way the Gruntfile is written using load-grunt-config is messing with my mind and I can't piece together how to isolate the server code.
Here's the solution I found:
As was suggested above, using pm2
However, when I ran
pm2 start grunt
I got an error saying that the grunt module did not exist, which was weird.
So I ended up writing a script which worked:
-- start.js --
var pm2 = require('pm2');
pm2.connect(function() {
pm2.start({
script : '/usr/local/bin/grunt', // Script to be run
args: '--force',
}, function(err, apps) {
pm2.disconnect();
});
});
After running node start.js from the command line, everything sailed smoothly.

How do I successfully notify Airbrake of a deployment when using capistrano to deploy a Node.js project?

This is a bit of an oddball question.
Capistrano 2.14.2
I'm using capistrano to deploy a couple of Node.js projects, and this works fine (from within the same rvm and gemset Ruby installation). However, I'd like to have Airbrake be notified of these deployments.
Using the 'airbrake' Node.js module, and calling
airbrake.trackDeployment({repo: '...'});
works, but not sure how to reliably call this just once at deploy time. If I call it within my server, then Airbrake is notified of a "deployment" every time my server starts, which is obviously not correct.
Adding
require 'airbrake/capistrano'
to deploy.rb definitely does not work.
How do others successfully use
airbrake.trackDeployment
?
You could create a simple js file you'd run locally (on your machine for example) that notifies airbrake as a last deploy task. You could for example use the backtick operator to run a task:
deploy.task :notify_airbrake do
`node notify_airbrake.js`
end
If you don't have node installed locally, you could also pick one of the servers to run the notification script through ssh:
deploy.task :notify_airbrake do
`ssh youserver "node notify_airbrake.js"`
end
Based on this solution http://dwradcliffe.com/2011/09/26/using-airbrake-with-node.html (which is clearly embedded in a Rails app.), I came up with the following, which depends solely on Javascript:
In my Node.js root directory, create a deploy.js file, like so:
var airbrake = require('airbrake').createClient("AIRBRAKE_API_KEY");
var deployment = {rev: process.argv[2],
repo: process.argv[3],
env: process.argv[4],
user: process.argv[5]};
airbrake.trackDeployment(deployment, function(err, params) {
if (err) {throw err}
console.log('Tracked deployment of %s to %s', params.rev, params.env);
})
In config/deploy.rb, add
require 'airbrake/capistrano'
and
namespace :airbrake do
desc "Notify Airbrake of a new deploy."
task :deploy do
system "node deploy.js #{current_revision} #{repository} #{stage} #{user}"
end
end

Can I tell foreman to reload the web app every time a request is made so I can develop decently?

A web app I am writing in JavaScript using node.js. I use Foreman, but I don't want to manually restart the server every time I change my code. Can I tell Foreman to reload the entire web app before handling an HTTP request (i.e. restart the node process)?
Here's an adjusted version of Pendlepants solution. Foreman looks for an .env file to read environment variables. Rather than adding a wrapper, you can just have Foreman switch what command it uses to start things up:
In .env:
WEB=node app.js
In dev.env:
WEB=supervisor app.js
In your Procfile:
web: $WEB
By default, Foreman will read from .env (in Production), but in DEV just run this:
foreman start -e dev.env
You can use rerun for this purpose
You might implement just 2 commands for this:
gem install rerun
rerun foreman start
Then rerun will automatically restart process after any change in your files.
If you use nodemon
, you can do
nodemon --exec "foreman start"
The problem isn't with Foreman so much as it's with how node doesn't reload code on new requests. The solution is to use an npm package like supervisor along with an environment wrapper for Foreman.
First, install supervisor:
npm install -g supervisor
Then, write a wrapper shell script that Foreman can call:
if [ "$NODE_ENV" == "production" ]; then
node /path/to/app.js
else
supervisor /path/to/app.js
fi
Set the wrapper script's permissions to executable by running chmod a+x /path/to/wrapper_script.sh
Lastly, update foreman to use the wrapper script. So in your Procfile:
web: /path/to/wrapper_script.sh
Now when you run Foreman and your node app isn't running in production, it should reload on every request.
I feel like Peter Ehrlich's comment on the original question deserves to be an answer on its own. I think a different Procfile for local/dev is definitely the best solution: https://stackoverflow.com/a/10790514/133720
You don't even need to install anything new if you use node-dev.
Your .env file loaded from Procfile:
NODECMD=node-dev
Your Procfile:
web: $NODECMD app/server.js
Your foreman command
foreman start -e dev.env -p 9786
And in your production env (heroku) set an environment variable:
NODECMD=node

Resources