|
1 | 1 | #!/bin/bash |
| 2 | +set -euo pipefail |
| 3 | + |
2 | 4 | # script to watch changes in WATCH_DIR and reload nginx on .conf file changes |
3 | 5 |
|
4 | | -export WATCH_DIR=${WATCH_DIR:-/etc/nginx} |
5 | | -export RELOADER_LOG=${RELOADER_LOG:-/var/log/nginx/reloader.log} |
6 | | -export RELOADER_DELAY=${RELOADER_DELAY:-2} |
| 6 | +WATCH_DIR="${WATCH_DIR:-/etc/nginx}" |
| 7 | +RELOADER_LOG="${RELOADER_LOG:-/var/log/nginx/reloader.log}" |
| 8 | +RELOADER_DELAY="${RELOADER_DELAY:-2}" |
| 9 | +FAIL_COUNT=0 |
| 10 | +MAX_FAILS=5 |
7 | 11 |
|
8 | 12 | log() { |
9 | 13 | local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1" |
10 | 14 | echo "$msg" |
11 | | - echo "$msg" >> "${RELOADER_LOG}" |
| 15 | + echo "$msg" >> "${RELOADER_LOG}" 2>/dev/null || true |
| 16 | +} |
| 17 | + |
| 18 | +error_exit() { |
| 19 | + log "ERROR: $1" |
| 20 | + exit 1 |
12 | 21 | } |
13 | 22 |
|
14 | | -log "Starting nginx-reloader, watching: ${WATCH_DIR} for *.conf files (delay: ${RELOADER_DELAY}s)" |
| 23 | +# pre-flight checks |
| 24 | +command -v inotifywait >/dev/null 2>&1 || error_exit "inotifywait not found, install inotify-tools" |
| 25 | +command -v nginx >/dev/null 2>&1 || error_exit "nginx not found" |
| 26 | +[[ -d "${WATCH_DIR}" ]] || error_exit "WATCH_DIR does not exist: ${WATCH_DIR}" |
| 27 | + |
| 28 | +# ensure log directory exists |
| 29 | +LOG_DIR=$(dirname "${RELOADER_LOG}") |
| 30 | +[[ -d "${LOG_DIR}" ]] || mkdir -p "${LOG_DIR}" |
| 31 | + |
| 32 | +log "Starting nginx-reloader" |
| 33 | +log "Config: WATCH_DIR=${WATCH_DIR} DELAY=${RELOADER_DELAY}s LOG=${RELOADER_LOG}" |
15 | 34 |
|
16 | 35 | while true |
17 | 36 | do |
18 | 37 | sleep "${RELOADER_DELAY}" |
19 | | - FILE=$(inotifywait --recursive --include '\.conf$' --format '%f' -e create -e modify -e delete -e move "${WATCH_DIR}" 2>/dev/null) |
20 | 38 |
|
21 | | - if [[ -z "${FILE}" ]]; then |
| 39 | + # run inotifywait and capture both output and exit code |
| 40 | + set +e |
| 41 | + OUTPUT=$(inotifywait --recursive --include '\.conf$' --format '%w%f %e' \ |
| 42 | + -e create -e modify -e delete -e move "${WATCH_DIR}" 2>&1) |
| 43 | + EXIT_CODE=$? |
| 44 | + set -e |
| 45 | + |
| 46 | + # handle inotifywait errors |
| 47 | + if [[ ${EXIT_CODE} -ne 0 ]]; then |
| 48 | + FAIL_COUNT=$((FAIL_COUNT + 1)) |
| 49 | + log "inotifywait failed (exit=${EXIT_CODE}, count=${FAIL_COUNT}): ${OUTPUT}" |
| 50 | + if [[ ${FAIL_COUNT} -ge ${MAX_FAILS} ]]; then |
| 51 | + error_exit "inotifywait failed ${MAX_FAILS} times, giving up" |
| 52 | + fi |
| 53 | + sleep 5 |
22 | 54 | continue |
23 | 55 | fi |
24 | 56 |
|
25 | | - log "Detected: ${FILE}" |
26 | | - nginx -t |
27 | | - if [[ $? -eq 0 ]]; then |
| 57 | + # reset fail count on success |
| 58 | + FAIL_COUNT=0 |
| 59 | + |
| 60 | + # parse output - format is "path event" |
| 61 | + FILE=$(echo "${OUTPUT}" | awk '{print $1}') |
| 62 | + EVENT=$(echo "${OUTPUT}" | awk '{print $2}') |
| 63 | + |
| 64 | + # skip if empty |
| 65 | + [[ -z "${FILE}" ]] && continue |
| 66 | + |
| 67 | + # only process .conf files (double check) |
| 68 | + [[ "${FILE}" != *.conf ]] && continue |
| 69 | + |
| 70 | + log "Detected: ${FILE} (${EVENT})" |
| 71 | + |
| 72 | + # test nginx config |
| 73 | + set +e |
| 74 | + TEST_OUTPUT=$(nginx -t 2>&1) |
| 75 | + TEST_CODE=$? |
| 76 | + set -e |
| 77 | + |
| 78 | + if [[ ${TEST_CODE} -eq 0 ]]; then |
28 | 79 | log "Config valid, reloading nginx" |
29 | | - nginx -s reload |
| 80 | + nginx -s reload || log "Reload failed" |
30 | 81 | else |
31 | | - log "Config test failed, skipping reload" |
| 82 | + log "Config test failed: ${TEST_OUTPUT}" |
32 | 83 | fi |
33 | 84 | done |
0 commit comments