How to run async commands in queue AND in background? - linux

I want to create a Shell script (.sh) using MacOS and LinuxOS (respectively). This is what I have made:
#!/bin/bash
redis-server &
mongod &
cd ~/some/path && npm start &
cd ~/some/path && ./ngrok http 3000 -region=eu &
echo "My Workspace has been started"
I want redis-server to be running in background, and only by the time that the redis-server was fully initiated I want then to run the mongod service. And so for and so on.
At the end of the script I want to see the My Workspace has been started log on the Terminal.
What happens now is that it runs all of them together, I can see mixin logs in the Terminal of the redis, and then of the mongo and then some from the npm and etc.
How can I achieve this?

You should wait for the previous command's successful execution I assume. That can be achieved like:
#!/bin/bash
redis-server && \
mongod &&\
cd ~/some/path && npm start &&\
cd ~/some/path && ./ngrok http 3000 -region=eu &&\
echo "My Workspace has been started"
This way every command depends on the previous one's execution. However if any of them` are not set up to exit after execution (which is very likely since the first two are services) it will never be finished properly.
So to solve this You can create some checks for running services, like:
#!/bin/bash
redis-server &
sleep $SOMEMINUTES &&\
ps WHATEVEROPTIONSYOUPREFER | grep redis && \
mongod &
You see the pattern here. Or You can rely on this for redis:
#!/bin/bash
redis-server &
sleep $SOMEREASONABLETIME && redis-cli ping && \
mongod &
cd ~/some/path && npm start &
cd ~/some/path && ./ngrok http 3000 -region=eu &
echo "My Workspace has been started"
For mongodb You might have to rely on ps or netcat to check the status as far as I know. Here You can find some examples.

Related

How to start fastapi ,react, node server using shell script file

I need to run many commands one by one to start my project instead of that i tried to put commands on shell script file
server.sh
#!/bin/bash
sudo systemctl start elasticsearch.service
sudo systemctl start kibana.service
cd fastapi
uvicorn main:app --reload --port 8000
cd ..
cd reactjs
npm i
npm start
cd ..
cd node
npm i
npm run dev
These are commands I put it in a .sh file, now problem is after uvicorn main:app --reload --port 8000 this command sh files failed to execute rest of the commands.
how to resolve this using .sh file or yaml file
You must run in background the three main scripts in your code:
uvicorn main:app --reload --port 8000 &
npm start &
npm run dev &
That & is used after a command to run this one in background, so the script will not stop in the first command (avicorn) and it will follow with the code.
And because of those commands will generate an output in the terminal (in the case you are running them from it) that output can be confused, so I would recommend redirect the output to a file for every command you run in background.
Your code could be like this:
#!/bin/bash
sudo systemctl start elasticsearch.service
sudo systemctl start kibana.service
cd fastapi
uvicorn main:app --reload --port 8000 > uvicorn.log &
cd ../reactjs
npm i
npm start > npmstart.log &
cd ../node
npm i
npm run dev > npmdev.log &
For killing those process you should use the kill command.
There are several options for killing, you can visit kill signals on Linux to understand how it works.
Or if you want to use a GUI, the system monitor might work, but you must know what PID is what you want to kill.
When a process starts this saves in $! its current PID (process ID), so you can use the next statement to show the PID:
echo $!
And when you want to kill the process, use:
kill -9 the_pid_shown_with_echo
So your code could be like this (but it's not enough in this case):
#!/bin/bash
sudo systemctl start elasticsearch.service
sudo systemctl start kibana.service
cd fastapi
uvicorn main:app --reload --port 8000 > uvicorn.log &
echo "Uvicorn ID: $!" | tee uvicornpid.txt
cd ../reactjs
npm i
npm start > npmstart.log &
echo "npm start ID: $!" | tee npmstart.txt
cd ../node
npm i
npm run dev > npmdev.log &
echo "npm run dev ID: $!" | tee npmrundev.txt
The statements with tee command like echo "Uvicorn ID: $!" | tee uvicornpid.txt are used for showing the text in the terminal and also redirect the output to a file. So you can check those files later for checking the PID's
But as I said, in this case this is not enough because unless with node this runs various process and if you kill the process by using the PID you got with $! this will kill that process (and maybe other one). But the process which is listening in that port, will stay running and when you run the app again, this will crash because the port is in use (unless you run the app in another port, but I would not recommend it).
You can use several commands for getting the PID you should kill.
The first way is using commands like:
pgrep node
This will return all PID which match with node word
ps -efl | grep -E "(node|PID)"
This will return an output with several columns and you will can see the PID of all process which match with node word and another information that might be useful.
Other useful commands the might be better for you are these:
lsof -i :4000
This will return the process running in the 4000 port (you will get the PID, the name of the process and more information)
fuser 4000/tcp
This only will return 4000/tcp and the PID of the process running in that port.
So, once you get the PID with one of those methods, you should kill the process with the kill command as I explained before.

Run script command on parallel

i’ve bash script which I need to run on it two command in parallel
For example I’m executing a command of npm install which takes some time (20 -50 secs)
and I run it on two different folders in sequence first npm install on books folder and the second
is for orders folder, is there a way to run both in parallel in shell script ?
For example assume the script is like following:
#!/usr/bin/env bash
dir=$(pwd)
cd $tmpDir/books/
npm install
grunt
npm prune production
cd $tmpDir/orders/
npm install
grunt
npm prune production
You could use & to run the process in the background, for example:
#!/bin/sh
cd $HOME/project/books/
npm install &
cd $HOME/project/orders/
npm install &
# if want to wait for the processes to finish
wait
To run and wait for nested/multiple processes you could use a subshell () for example:
#!/bin/sh
(sleep 10 && echo 10 && sleep 1 && echo 1) &
cd $HOME/project/books/
(npm install && grunt && npm prune production ) &
cd $HOME/project/orders/
(npm install && grunt && npm prune production ) &
# waiting ...
wait
In this case, notice the that the commands are within () and using && that means that only the right side will be evaluated if the left size succeeds (exit 0) so for the example:
(sleep 10 && echo 10 && sleep 1 && echo 1) &
It creates a subshell putting things between ()
runs sleep 10 and if succeeds && then runs echo 10, if succeeds && then run sleep 1 and if succeeds && then runs echo 1
run all this in the background by ending the command with &

How to make Docker restart a Container after a period of time?

How to restart a Node JS application running inside a docker container after a period of time without user input (Automated)?
I have a Docker Container with an application whose underlying architecture showed to hang once in a while. The idea is to simply restart the application after a period of time. This should all happen automated. Consider the following Dockerfile.
FROM node:6.11.1
ENV HOME=/usr/src/app/
# Create app directory
RUN mkdir -p $HOME
WORKDIR $HOME
COPY npm-shrinkwrap.json $HOME
RUN npm install
# Bundle app source
COPY . $HOME
EXPOSE 3000
CMD ["npm", "start"]
After npm start the application either was successfull or not. In most cases it runs successull. So for the other cases I would like to simply restart the whole application after a period of time.
Install Node cron
$ npm install --save node-cron
Import node-cron and schedule a task:
var cron = require('node-cron');
cron.schedule('* * * * *', function(){
console.log('running a task every minute');
});
Combining the following from ivanvanderbyl.
COPY entrypoint.sh /entrypoint
RUN chmod +x /entrypoint
ENTRYPOINT ["/entrypoint", "node", "--harmony-async-await"]
And the official documentation on ENTRYPOINT, Run multiple services in a container and reading through a bunch of Bash tutorials I came up with the following solution.
#!/bin/bash
echo " # Starting Scraper"
node index.js -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start node: $status"
exit $status
fi
echo " # Init Restart-Routine. Beware, console will freeze!"
while :
do
echo "[1]/[4] Sleep"
sleep 5
echo "[2]/[4] Kill node process"
pkill -f "node index.js"
echo "[3]/[4] Sleep 2 seconds to make sure everything is down"
sleep 2
echo "[4]/[4] Start NodeJS"
node index.js
done
The final product does the following: When I start Docker it starts my node application and after a period of time it kills the node process BUT NOT the docker process and restarts it. Exactly what I was looking for.

EC2 ubuntu launch node server on reboot not working

I'm trying to launch an express app when my ec2 machine starts. I've a startup script that is:
#!/bin/bash
echo "will reroute traffic" >> /home/ubuntu/log.logs
sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -A INPUT -p tcp -m tcp --sport 80 -j ACCEPT
sudo iptables -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
echo "will kill node" >> /home/ubuntu/log.logs
if pgrep node &> /dev/null ; then killall -KILL node ; fi
if pgrep nodejs &> /dev/null ; then killall -KILL nodejs ; fi
echo "will run node server" >> /home/ubuntu/log.logs
cd server && npm install && npm run build && npm run start </dev/null &>/dev/null &
echo "has run node server" >> /home/ubuntu/log.logs
If I launch it from the console, it starts the server, exits and the server runs fine.
To launch it, I've added those lines to /etc/rc.local:
rm -f /home/ubuntu/log.logs
echo "will run" >> /home/ubuntu/log.logs
/bin/bash /home/ubuntu/startup.sh
echo "has run" >> /home/ubuntu/log.logs
After rebooting, the server is not responding and it looks like it has not started (the server logs ticks when running that are not there)
the output in log.logs looks fine:
will run
will will reroute traffic
will kill node
will run node server
has run node server
has run
so everything seems to have been executed, but the node app is not running, which I confirmed by running top | grep node that returns nothing.
I found that the cheap (or free) AWS VMs got CPU/network throttled causing npm installs etc. to fail. Maybe use a VPS that is a better value or try yarn. Also make it log the npm stuff to a file instead of dev/null.
It turned out that I installed npm and node through nvm, and that nvm adds a script to .bashrc that will load those libraries. To start my script on reboot, I was using cron that is not sourcing .bashrc. Additionally, the default .bashrc on AWS EC2 ubuntu instances starts with a check on wether it's been run from a terminal or not, and escape it it's not been run from a terminal. So sourcing it from cron has no effect.
I didn't see that since the failing line
cd server && npm install && npm run build && npm run start
was not logging anything
I ended up manually sourcing the path to npm and node

How to run Node.js as a background process and never die?

I connect to the linux server via putty SSH. I tried to run it as a background process like this:
$ node server.js &
However, after 2.5 hrs the terminal becomes inactive and the process dies. Is there anyway I can keep the process alive even with the terminal disconnected?
Edit 1
Actually, I tried nohup, but as soon as I close the Putty SSH terminal or unplug my internet, the server process stops right away.
Is there anything I have to do in Putty?
Edit 2 (on Feb, 2012)
There is a node.js module, forever. It will run node.js server as daemon service.
nohup node server.js > /dev/null 2>&1 &
nohup means: Do not terminate this process even when the stty is cut
off.
> /dev/null means: stdout goes to /dev/null (which is a dummy
device that does not record any output).
2>&1 means: stderr also goes to the stdout (which is already redirected to /dev/null). You may replace &1 with a file path to keep a log of errors, e.g.: 2>/tmp/myLog
& at the end means: run this command as a background task.
Simple solution (if you are not interested in coming back to the process, just want it to keep running):
nohup node server.js &
There's also the jobs command to see an indexed list of those backgrounded processes. And you can kill a backgrounded process by running kill %1 or kill %2 with the number being the index of the process.
Powerful solution (allows you to reconnect to the process if it is interactive):
screen
You can then detach by pressing Ctrl+a+d and then attach back by running screen -r
Also consider the newer alternative to screen, tmux.
You really should try to use screen. It is a bit more complicated than just doing nohup long_running &, but understanding screen once you never come back again.
Start your screen session at first:
user#host:~$ screen
Run anything you want:
wget http://mirror.yandex.ru/centos/4.6/isos/i386/CentOS-4.6-i386-binDVD.iso
Press ctrl+A and then d. Done. Your session keeps going on in background.
You can list all sessions by screen -ls, and attach to some by screen -r 20673.pts-0.srv command, where 0673.pts-0.srv is an entry list.
This is an old question, but is high ranked on Google. I almost can't believe on the highest voted answers, because running a node.js process inside a screen session, with the & or even with the nohup flag -- all of them -- are just workarounds.
Specially the screen/tmux solution, which should really be considered an amateur solution. Screen and Tmux are not meant to keep processes running, but for multiplexing terminal sessions. It's fine, when you are running a script on your server and want to disconnect. But for a node.js server your don't want your process to be attached to a terminal session. This is too fragile. To keep things running you need to daemonize the process!
There are plenty of good tools to do that.
PM2: http://pm2.keymetrics.io/
# basic usage
$ npm install pm2 -g
$ pm2 start server.js
# you can even define how many processes you want in cluster mode:
$ pm2 start server.js -i 4
# you can start various processes, with complex startup settings
# using an ecosystem.json file (with env variables, custom args, etc):
$ pm2 start ecosystem.json
One big advantage I see in favor of PM2 is that it can generate the system startup script to make the process persist between restarts:
$ pm2 startup [platform]
Where platform can be ubuntu|centos|redhat|gentoo|systemd|darwin|amazon.
forever.js: https://github.com/foreverjs/forever
# basic usage
$ npm install forever -g
$ forever start app.js
# you can run from a json configuration as well, for
# more complex environments or multi-apps
$ forever start development.json
Init scripts:
I'm not go into detail about how to write a init script, because I'm not an expert in this subject and it'd be too long for this answer, but basically they are simple shell scripts, triggered by OS events. You can read more about this here
Docker:
Just run your server in a Docker container with -d option and, voilá, you have a daemonized node.js server!
Here is a sample Dockerfile (from node.js official guide):
FROM node:argon
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install
# Bundle app source
COPY . /usr/src/app
EXPOSE 8080
CMD [ "npm", "start" ]
Then build your image and run your container:
$ docker build -t <your username>/node-web-app .
$ docker run -p 49160:8080 -d <your username>/node-web-app
Always use the proper tool for the job. It'll save you a lot of headaches and over hours!
another solution disown the job
$ nohup node server.js &
[1] 1711
$ disown -h %1
nohup will allow the program to continue even after the terminal dies. I have actually had situations where nohup prevents the SSH session from terminating correctly, so you should redirect input as well:
$ nohup node server.js </dev/null &
Depending on how nohup is configured, you may also need to redirect standard output and standard error to files.
Nohup and screen offer great light solutions to running Node.js in the background. Node.js process manager (PM2) is a handy tool for deployment. Install it with npm globally on your system:
npm install pm2 -g
to run a Node.js app as a daemon:
pm2 start app.js
You can optionally link it to Keymetrics.io a monitoring SAAS made by Unitech.
$ disown node server.js &
It will remove command from active task list and send the command to background
I have this function in my shell rc file, based on #Yoichi's answer:
nohup-template () {
[[ "$1" = "" ]] && echo "Example usage:\nnohup-template urxvtd" && return 0
nohup "$1" > /dev/null 2>&1 &
}
You can use it this way:
nohup-template "command you would execute here"
Have you read about the nohup command?
To run command as a system service on debian with sysv init:
Copy skeleton script and adapt it for your needs, probably all you have to do is to set some variables. Your script will inherit fine defaults from /lib/init/init-d-script, if something does not fits your needs - override it in your script. If something goes wrong you can see details in source /lib/init/init-d-script. Mandatory vars are DAEMON and NAME. Script will use start-stop-daemon to run your command, in START_ARGS you can define additional parameters of start-stop-daemon to use.
cp /etc/init.d/skeleton /etc/init.d/myservice
chmod +x /etc/init.d/myservice
nano /etc/init.d/myservice
/etc/init.d/myservice start
/etc/init.d/myservice stop
That is how I run some python stuff for my wikimedia wiki:
...
DESC="mediawiki articles converter"
DAEMON='/home/mss/pp/bin/nslave'
DAEMON_ARGS='--cachedir /home/mss/cache/'
NAME='nslave'
PIDFILE='/var/run/nslave.pid'
START_ARGS='--background --make-pidfile --remove-pidfile --chuid mss --chdir /home/mss/pp/bin'
export PATH="/home/mss/pp/bin:$PATH"
do_stop_cmd() {
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
$STOP_ARGS \
${PIDFILE:+--pidfile ${PIDFILE}} --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
rm -f $PIDFILE
return $RETVAL
}
Besides setting vars I had to override do_stop_cmd because of python substitutes the executable, so service did not stop properly.
Apart from cool solutions above I'd mention also about supervisord and monit tools which allow to start process, monitor its presence and start it if it died. With 'monit' you can also run some active checks like check if process responds for http request
For Ubuntu i use this:
(exec PROG_SH &> /dev/null &)
regards
Try this for a simple solution
cmd & exit

Resources