diff --git a/hugegraph-server/hugegraph-dist/docker/README.md b/hugegraph-server/hugegraph-dist/docker/README.md index 9214aa830e..07f5c5ae08 100644 --- a/hugegraph-server/hugegraph-dist/docker/README.md +++ b/hugegraph-server/hugegraph-dist/docker/README.md @@ -144,3 +144,30 @@ native `HEALTHCHECK` instructions. `docker ps` shows real health status: | `hugegraph/hugegraph-store` | `GET /v1/health` on port 8520 | The entrypoints supervise the Java process directly — when Java exits, the container exits. If started with a restart policy (the provided compose files use `restart: unless-stopped`), Docker will bring it back automatically. The old cron-based monitor (`-m true`) is for VM/bare-metal deployments only and is not used in Docker images. + +## 7. Server Startup Timeout + +The entrypoint gives the Server a fixed budget to answer on its REST port and +ends the container when the budget runs out. It is 120 seconds by default. Set +`HG_SERVER_STARTUP_TIMEOUT_S` to a whole number of seconds between 1 and 86400 +to change it: + +```bash +docker run -itd --name=graph -p 8080:8080 -e HG_SERVER_STARTUP_TIMEOUT_S=450 hugegraph/hugegraph:1.7.0 +``` + +Raise it on slow or contended hosts, and wherever an orchestrator already owns +the startup budget through a probe of its own: a startup probe cannot extend a +container that has already ended the JVM it was waiting for. Anything outside +the accepted range, an empty value included, stops the container at startup +instead of silently falling back to the default. + +Raising this budget does not move the health check described in section 6, +which runs on a clock of its own. The images set `--interval=15s +--start-period=90s --retries=3`, so a container given a longer startup budget +is reported `unhealthy` around 135 seconds while the entrypoint is still +legitimately waiting; raise it with `--health-start-period` on `docker run`. +The Compose files replace those values with their own (`start_period: 60s`, +`interval: 10s`, `retries: 30`, so roughly 360 seconds), and anything gated on +`depends_on: condition: service_healthy`, Hubble included, waits on that budget +rather than on this variable. Move the two together. diff --git a/hugegraph-server/hugegraph-dist/docker/docker-entrypoint-test.sh b/hugegraph-server/hugegraph-dist/docker/docker-entrypoint-test.sh index 6e22885ebe..6a38520bb3 100755 --- a/hugegraph-server/hugegraph-dist/docker/docker-entrypoint-test.sh +++ b/hugegraph-server/hugegraph-dist/docker/docker-entrypoint-test.sh @@ -35,6 +35,7 @@ backend=rocksdb EOF cat > "${TEST_HOME}/bin/start-hugegraph.sh" <<'EOF' #!/usr/bin/env bash +printf '%s\n' "$*" >> ./docker/start-hugegraph-args exit 0 EOF cat > "${TEST_HOME}/bin/init-store.sh" <<'EOF' @@ -232,4 +233,60 @@ rm -f "${TEST_HOME}/docker/init_complete" ) grep -Fqx -- '-n' "${TEST_HOME}/docker/init-store-password" +last_start_args() { tail -n 1 "${TEST_HOME}/docker/start-hugegraph-args"; } + +[[ "$(last_start_args)" == *"-t 120"* ]] + +( + cd "${TEST_HOME}" + HG_SERVER_STARTUP_TIMEOUT_S=450 bash ./docker-entrypoint.sh +) +[[ "$(last_start_args)" == *"-t 450"* ]] + +( + cd "${TEST_HOME}" + HG_SERVER_STARTUP_TIMEOUT_S=86400 bash ./docker-entrypoint.sh +) +[[ "$(last_start_args)" == *"-t 86400"* ]] + +# An empty value is a set value, not an absent one: Compose writes it whenever +# an interpolated host variable is missing. 2m is the shape of a typo, and the +# two large values bracket the point where the deadline arithmetic in +# wait_for_startup would wrap negative and end the wait before its first probe. +for invalid_timeout in "" " " 0 +5 2m 86401 9223372036854775807; do + start_calls_before_invalid=$(wc -l < "${TEST_HOME}/docker/start-hugegraph-args") + init_calls_before_invalid=$(wc -l < "${TEST_HOME}/docker/init-store-calls") + if ( + cd "${TEST_HOME}" + HG_SERVER_STARTUP_TIMEOUT_S="${invalid_timeout}" \ + bash ./docker-entrypoint.sh + ); then + echo "startup timeout '${invalid_timeout}' unexpectedly succeeded" >&2 + exit 1 + fi + # The server must not have started, and the guard must have run ahead of + # init-store, as the comment above it in the entrypoint claims. Spelled + # with an explicit exit rather than a bare [[ ]]: bash 3.2, still the + # /bin/bash of macOS, does not apply set -e to a failing [[ ]], so a bare + # assertion passes silently there while CI catches the regression. + [[ "$(wc -l < "${TEST_HOME}/docker/start-hugegraph-args")" -eq \ + "${start_calls_before_invalid}" ]] || { + echo "startup timeout '${invalid_timeout}' started the server" >&2 + exit 1 + } + [[ "$(wc -l < "${TEST_HOME}/docker/init-store-calls")" -eq \ + "${init_calls_before_invalid}" ]] || { + echo "startup timeout '${invalid_timeout}' was rejected only after" \ + "init-store ran" >&2 + exit 1 + } +done + +# An unset variable still keeps the historical default. +( + cd "${TEST_HOME}" + bash ./docker-entrypoint.sh +) +[[ "$(last_start_args)" == *"-t 120"* ]] + echo "PASS: Docker entrypoint configures HStore discovery and authentication" diff --git a/hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh b/hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh index fe9974c430..b5ba2de34f 100755 --- a/hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh +++ b/hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh @@ -98,6 +98,29 @@ if [[ -n "${HG_SERVER_AUTH_TOKEN_SECRET:-}" ]]; then fi fi +# How long the entrypoint lets the server take to answer on its REST port +# before it gives up and ends the container. An orchestrator that already +# owns this budget through a startup probe needs to raise it, otherwise the +# container terminates a JVM that is still starting and the probe never gets +# to decide. Validated here so a bad value fails before init-store runs, +# rather than reaching the arithmetic in wait_for_startup: that deadline is +# $((now_s + timeout_s)), which wraps negative near the 64-bit ceiling and +# makes the wait exit before its first probe, the very failure this variable +# exists to avoid. The five-digit bound keeps this comparison in range too, +# and a day is already far past any real start. Plain '-' rather than ':-', +# so an explicitly empty value is rejected instead of quietly becoming the +# default: Compose interpolation such as ${SOME_VAR:-} yields empty, not +# unset, whenever the host variable is missing. +SERVER_STARTUP_TIMEOUT_MAX_S=86400 +SERVER_STARTUP_TIMEOUT_S="${HG_SERVER_STARTUP_TIMEOUT_S-120}" +if [[ ! "${SERVER_STARTUP_TIMEOUT_S}" =~ ^[1-9][0-9]{0,4}$ ]] || + (( SERVER_STARTUP_TIMEOUT_S > SERVER_STARTUP_TIMEOUT_MAX_S )); then + log "ERROR: HG_SERVER_STARTUP_TIMEOUT_S must be a whole number of" \ + "seconds from 1 to ${SERVER_STARTUP_TIMEOUT_MAX_S}," \ + "got '${SERVER_STARTUP_TIMEOUT_S}'" + exit 1 +fi + if [[ -n "${PASSWORD:-}" && "${HG_SERVER_REQUIRE_AUTH_TOKEN_SECRET:-false}" == "true" && -z "${HG_SERVER_AUTH_TOKEN_SECRET:-}" ]]; then @@ -217,7 +240,7 @@ else ./bin/init-store.sh fi -./bin/start-hugegraph.sh -j "${JAVA_OPTS:-}" -t 120 +./bin/start-hugegraph.sh -j "${JAVA_OPTS:-}" -t "${SERVER_STARTUP_TIMEOUT_S}" # Post-startup cluster stabilization check (hstore only — rocksdb has no partitions) ACTUAL_BACKEND=$(grep -E '^[[:space:]]*backend[[:space:]]*=' "${GRAPH_CONF}" | head -n 1 | sed 's/.*=//' | tr -d '[:space:]' || true)