I am trying to run a node.js script from cron. It is supposed to read a .json-File, make an API call and then write the response to a .json-File.
When executing manually everything works fine.
This does it's job
sudo node ~/bots/gtaa/index.js
sudo crontab -e
29 9 * * 1-5 /usr/bin/node ~/bots/gtaa/index.js >> ~/gtaa-bot.log 2>&1
grep cron /var/log/syslog
May 11 09:29:01 raspberrypi CRON[54381]: (root) CMD (/usr/bin/node ~/bots/gtaa/index.js >> ~/gtaa-bot.log 2>&1)
My index.js uses the local .env-File
require('dotenv').config({ path: __dirname + '/.env' })
There also is no gtaa-bot.log-File in the home directory.
A very similar question has been asked here but there are no useful answers provided.
Well I have experienced this issue, more recently using Ubuntu 20.04.4 LTS
Ultimately what ends up happening is cron runs in a different environment and most likely is unable to find the correct path to node.
There are some ways to configure this, however I found a much easier solution ended up being to just have cron execute a bash script, that runs nvm and/or node.
For example, I have this setup to run every 20 minutes:
20 * * * * /bin/bash/ /home/user/nvm_cron.sh
And in my nvm_cron.sh file:
# Load nvm
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm use 16.14.0
# Run node program
cd /home/user/folder && node start.js
Dont forget to make sure the nvm_cron.sh file is executable
This way I have control over the version of node that I want to run for the script, and don't have to worry about messing with cron.
Related
I have a programm called opencanary running at a virtual environment at my Raspberry Pi with Ubuntu 18.04 installed. I want to restart it every 30 Minutes using crontab. For testing I set the script to run every 3 Minutes as you can see below.
When I execute the script manually it's working fine. When using crontab to run it it doesn't and I can't find out why it fails.
This is what my script looks like:
#!/bin/bash
SHELL=/bin/sh
. /home/pi/.bashrc
source /home/pi/canary-env/bin/activate && cd opencanary && opencanaryd --restart
After creating the script I added it to crontab -e:
*/3 * * * * /home/pi/restartOC.sh>>test.log
When I look at the cron.log file I can see that the script is executed:
Sep 29 08:33:01 DiskStation CRON[20880]: (pi) CMD (cd /home/pi && sh restartOC.sh>>test.log)
the test.log file stays empty.
Does someone know what I am doing wrong?
Edit 05.10.2021
At the github of opencanary I was told that I don't have to use the 'cd opencanary'. I followed the advice and edited my script:
#!/bin/bash
SHELL=/bin/sh
. /home/pi/.bashrc
source /home/pi/canary-env/bin/activate && opencanaryd --restart
The script is still working when executed manual but The Problem does still exist when running the script from cron.
I solved the problem by calling 'which opencanaryd' at the terminal
this will return the path where the opencanaryd command is located.
In my case it is /usr/local/bin/opencanaryd
With this knowledge it is possible to edit the script so cron can find the command:
#!/bin/bash
SHELL=/bin/sh
. /home/pi/.bashrc
cd /usr/local/bin/ && . opencanaryd --restart
I have a script that I call from a cron job. The script is
#!/bin/bash
python /home/ubuntu/gateway-haproxy-config.py | tee /etc/haproxy/haproxy.cfg.new
DIFF=$(diff /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.new)
if [ "$DIFF" != "" ]
then
mv /etc/haproxy/haproxy.cfg.new /etc/haproxy/haproxy.cfg
service haproxy restart
else
echo "unmodified"
fi
The script works exactly as expected when I run it from a shell prompt.
I installed it as a cron job as follows (for root using sudo crontab -e):
* * * * * cd /home/ubuntu && ./gateway-config-cron
When the cron runs, the script successfully writes a new configuration file, does the diff and even replaces the old one with the new one when the diff is not empty.
The service haproxy restart never happens when running as a cron job. I am forced to manually restart the service.
This might have been a path related problem I was able to make it work as expected by providing the full path to service.
#!/bin/bash
python /home/ubuntu/gateway-haproxy-config.py | tee /etc/haproxy/haproxy.cfg.new
DIFF=$(diff /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.new)
if [ "$DIFF" != "" ]
then
mv /etc/haproxy/haproxy.cfg.new /etc/haproxy/haproxy.cfg
/usr/sbin/service haproxy restart
else
echo "unmodified"
fi
I am running a bash script that transfers files to my AWS bucket.If i run the bash script through my terminal it works fine (via ./myBash.sh).
However I put it in my crontab but there it doesn't work.This is my bash script
#!/bin/bash
s3cmd put /home/anonymous/commLogs.txt s3://myBucket/
echo transfer completed
echo now listing files in the s3 bucket
s3cmd ls s3://myBucket/
echo check
And this is my crontab-
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
46 13 * * * /bin/bash myBash.sh
And here is a list of things i have aready tried -
1)tried running the crontab with a node app to test whether crontab was working(the answer was yes)
2)tried running the crontab without the SHELL and PATH
3)Tried running the bash script from cron using sudo (46 13 * * * sudo myBash.sh)
4)tried running the bash without the /bin/bash
5) Searched many sites on the net for an answer without satisfactory results
Can anyone help me with what the problem may be?(I am running Ubuntu 14.04)
After a long time getting the same error, I just did this :
SHELL=/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin
* * * * * /bin/bash /home/joaovitordeon/Documentos/test.sh
For anyone coming to this post.
I was having same problem and reason was crontab was running under root user and s3cmd was configured under ubuntu user.
so need to copy .s3cfg to root
cp -i /home/ubuntu/.s3cfg /root/.s3cfg
Excuse me if the subject is vague, but I tried to describe my problem to the best of my possibilities. I have my raspberry pi which I want to deploy to using codeship. Rsyncing the files works perfectly, but when I am to restart my application using pm2 my problem occurs.
I have installed node and pm2 using the node version manager NVM.
ssh pi#server.com 'source /home/pi/.bashrc; cd project; pm2 restart app.js -x -- --prod'0 min 3 sec
bash: pm2: command not found
I have even added:
shopt -s expand_aliases in the bottom of my bashrc but it doesn't help.
How can I make it restart my application after I have done a deploy? Thanks in advance for your sage advice and better wisdom!
EDIT 1: My .bashrc http://pastie.org/10529200
My $PATH: /home/pi/.nvm/versions/node/v4.2.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
EDIT 2: I added /home/pi/.nvm/versions/node/v4.2.0/bin/pm2 which is the full path to pm2 and now I get the following error: /usr/bin/env: node: No such file or directory
It seems that even if I provide the full path, node isn't executed.
I think the problem is the misinterpretation that the shell executing node has a full environment like an interactive ssh session does. Most likely this is not the case.
When a SSH session spawns a shell it goes through a lot of gyrations to build an environment suitable to work with interactively. Things like inheriting from the login process, reading /etc/profile, reading ~/.profile. But in the cases where your executing bash directly this isn't always guaranteed. In fact the $PATH might be completely empty.
When /usr/bin/env node executes it looks for node in your $PATH which in a non-interactive shell could be anything or empty.
Most systems have a default PATH=/bin:/usr/bin typically /usr/local/bin is not included in the default environment.
You could attempt to force a login with ssh using ssh … '/bin/bash -l -c "…"'.
You can also write a specialized script on the server that knows how the environment should be when executed outside of an interactive shell:
#!/bin/bash
# Example shell script; filename: /usr/local/bin/my_script.sh
export PATH=$PATH:/usr/local/bin
export NODE_PATH=/usr/local/share/node
export USER=myuser
export HOME=/home/myuser
source $HOME/.nvm/nvm.sh
cd /usr/bin/share/my_script
nvm use 0.12
/usr/bin/env node ./script_name.js
Then call it through ssh: ssh … '/usr/local/bin/my_script.sh'.
Beyond these ideas I don't see how to help further.
Like Sukima said, the likelihood is that this is due to an environment issue - SSH'ing into a server does not set up a full environment. You can, however, get around much of this by simply calling /etc/profile yourself at the start of your command using the . operator (which is the same as the "source" command):
ssh pi#server.com '. /etc/profile ; cd project; pm2 restart app.js -x -- --prod'
/etc/profile should itself be set up to call the .bashrc of the relevant user, which is why I have removed that part. I used to have to do this quite a lot for quick proof-of-concept scripts at a previous workplace. I don't know if it would be considered a nasty hack for a more permanent script, but it certainly works, and would require minimal modification to your existing script should that be an issue.
For me I have to load :nvm as I installed node and yarn using :nvm
To load :nvm when ssh remote execution, we call
ssh :user#:host 'source ~/.nvm/nvm.sh; :other_commands_here'
Try:
ssh pi#server.com 'bash -l -c "source /home/pi/.bashrc; cd project; pm2 restart app.js -x -- --prod"'
You should enable some environment values by "source" or dot command ".". Here is an example.
ssh pi#server.com '. /home/pi/.nvm/nvm.sh; cd project; pm2 restart app.js -x -- --prod'
What worked for me was adding this to my .bash_profile:
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
Source: https://stackoverflow.com/a/820533/1824444
Quite simply, I have node script that I want to execute once a month.
30 6 1 * * node /home/steve/example/script.js
But this doesn't work, presumably because of path or the shell the command is being ran under. I've tried the following means of executing node via cron (tested with -v):
steve#atom:~$ node -v
v0.4.2
steve#atom:~$ sh node -v
sh: Can't open node
steve#atom:~$ bash node -v
/usr/local/bin/node: /usr/local/bin/node: cannot execute binary file
steve#atom:~$ /usr/local/bin/node -v
v0.4.2
steve#atom:~$ sh /usr/local/bin/node -v
/usr/local/bin/node: 1: Syntax error: "(" unexpected
steve#atom:~$ bash /usr/local/bin/node -v
/usr/local/bin/node: /usr/local/bin/node: cannot execute binary file
I've ran out of ideas to try, any advice?
just provide the full path to node /usr/local/bin/node in your cron job like:
30 6 1 * * /usr/local/bin/node /home/steve/example/script.js
These answers here saying using absolute path will all cause major problems for running a larger node app!
Real Complete Solution
Edit Cron Jobs
crontab -e
Find Node Path
which node
CD into the destination folder, then Change Cron Job according to Node Path and run script
*/2 * * * * cd /home/destination/path && /bin/node index.js
This will then allow you to run a full NodeJS application without all the errors like how using an absolute path for your index.js file.
Additionally, just put #!/usr/local/bin/node at the top of the script you want to execute. Then it will automatically know to execute the script with node. Make sure the file is executable as well.
You can also specify paths to binary files on top of your user crontab like:
PATH=/bin:/usr/bin:/usr/local/bin
* * * * * cd your/path && node foo.js
* * * * * cd your/path && npm run bar
in my laptop using Linux mint the given path not working so i used this to get a work around.
$ which node
$ /usr/bin/node
this worked for me.
This also works for user-level cron jobs
*/2 * * * * cd /home/destination/path && $(which node) index.js
I don't know if changing your relative paths in your script to absolute paths is a good idea
(what happens when your file system changes or you deploy in another environment?)
You could try wrapping it in a shell script, setting some environment variables in the crontab execution. (specifically PATH & NODE_PATH for starters)
Try my suggestion for this similar question:
https://stackoverflow.com/a/27823675/608269
NVM users:
Save the following script (say, cronjob.env.sh) anywhere at your PATH (let's say: $HOME/bin). Remember to make it executable (chmod +x). Replace 'username' with your user name as well:
#!/bin/bash
export NVM_DIR="/home/username/.nvm" #replace "username" with your user name
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
Edit cronjob:
crontab -e
Insert/edit your job:
0 0 * * * (. ~/bin/cronjob.env.sh; ~/bin/my-script-with-node-cmd.sh)
Calling node command (instead of some shell script), like the below job, works as well:
*/1 * * * * (. ~/bin/cronjob.env.sh; node ~/index.js)
PM2 users:
A different approach is using pm2, with --cron option, which accepts cron patterns (inside quotation marks):
pm2 start index.js --no-autorestart --cron "0 0 * * *"
--no-autorestart is for one-time scripts (otherwise, it will be restarted every time it is completed).
Use absolute paths for the node alias and the file to be run.
Edit Cron Jobs
crontab -e
Entry to Run Our Node File
This will run every minute.
*/1 * * * * * /bin/node /public/test.js
Full Tutorial
https://askmacgyver.com/blog/tutorial/how-to-run-node-scripts-from-a-cron-job
If you want to preserve the nvm functionality and allow your code to get an updated node version without needing to change the cron job info, put your job in a shell script that first sets up nvm, switches to proper node version, then runs the actual job. Here is an example for a project called invoicing that includes a cron script in its package.json.
File invoicing.sh:
#!/bin/bash
cd /home/produser/invoicing
export NVM_DIR="/home/produser/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
npm run cron
Then set this up as the command in your cron job listing:
0 16 1 * * produser /home/produser/invoicing/invoicing.sh
Now, if you change the node version in your project and update your .nvmrc with the proper version number and pull the new code onto the server, the next time the cron job runs it will run with version of node specified. Note that you must also make sure the server has the required node version.