Home > Software design >  How to gracefully shutdown nginx
How to gracefully shutdown nginx

Time:06-05

I am trying to use Heroku nginx buildpack and my problem is that nginx does not handle sigterm as graceful shutdown, so I am trying to modify bash script that runs nginx to do that. Also I would like to learn more about bash.

Here is script:

#!/usr/bin/env bash

psmgr=/tmp/nginx-buildpack-wait
rm -f $psmgr
mkfifo $psmgr

# Evaluate config to get $PORT
erb config/nginx.conf.erb > config/nginx.conf

n=1
while getopts :f option ${@:1:2}
do
  case "${option}"
  in
    f) FORCE=$OPTIND; n=$((n 1));;
  esac
done

# Initialize log directory.
mkdir -p logs/nginx
touch logs/nginx/access.log logs/nginx/error.log
echo 'buildpack=nginx at=logs-initialized'

# Start log redirection.
(
  # Redirect nginx logs to stdout.
  tail -qF -n 0 logs/nginx/*.log
  echo 'logs' >$psmgr
) &

# Start App Server
(
  # Take the command passed to this bin and start it.
  # E.g. bin/start-nginx bundle exec unicorn -c config/unicorn.rb
  COMMAND=${@:$n}
  echo "buildpack=nginx at=start-app cmd=$COMMAND"
  $COMMAND
  echo 'app' >$psmgr
) &

if [[ -z "$FORCE" ]]
then
  FILE="/tmp/app-initialized"

  # We block on app-initialized so that when nginx binds to $PORT
  # are app is ready for traffic.
  while [[ ! -f "$FILE" ]]
  do
    echo 'buildpack=nginx at=app-initialization'
    sleep 1
  done
  echo 'buildpack=nginx at=app-initialized'
fi

# Start nginx
(
  # We expect nginx to run in foreground.
  # We also expect a socket to be at /tmp/nginx.socket.
  echo 'buildpack=nginx at=nginx-start'
  bin/nginx -p . -c config/nginx.conf
  echo 'nginx' >$psmgr
) &

# This read will block the process waiting on a msg to be put into the fifo.
# If any of the processes defined above should exit,
# a msg will be put into the fifo causing the read operation
# to un-block. The process putting the msg into the fifo
# will use it's process name as a msg so that we can print the offending
# process to stdout.
read exit_process <$psmgr
echo "buildpack=nginx at=exit process=$exit_process"
exit 1

Aim is to handle SIGTERM signal in a way that node server and nginx should close, with this script everything is instanlty killed. My node server is handling signals properly.

Thanks for help.

Edit 1: I have already patched nginx to use SIGTERM in place of SIGQUIT. I know I have to trap SIGTERM so it does not kill script but then script never exits and it is only killed after 30 seconds which is Heroku timeout for process to die.

CodePudding user response:

Here is my implementation, https://github.com/nenadfilipovic/heroku-buildpack-nginx. It is working excellent in production.

  • Related