mirror of
https://github.com/Twigpine/node.git
synced 2026-11-09 18:08:02 -10:00
* fix(docker): reap orphan processes via tini + init, cap pids The node runs as PID 1 in the container and never reaps reparented orphans, so git grandchildren (e.g. pack-objects left behind when a served clone disconnects) accumulate as zombies until fork() fails with EAGAIN. Run under tini and set compose init: true so reparented orphans are reaped, and add pids_limit as a blast-radius cap. Refs #53 * fix(node): reap leaked git child processes (#53) Serving git over smart-HTTP could leak zombie processes that, over weeks, exhaust the PID table until fork() fails with EAGAIN and all git operations break until restart. The serve path (run_git_service) now runs git in its own process group and SIGKILLs that group when the request future is dropped (client disconnect) or returns early, so git and its pack-objects child are torn down together instead of orphaning the grandchild to PID 1 as a zombie. A drop guard, disarmed once the request completes cleanly, owns this teardown. create_issue and build_filtered_pack spawned a std Child and dropped it unwaited if the stdin write failed (and build_filtered_pack could panic on a missing stdin handle). Both now always wait the child before surfacing any error, so the failure path cannot leak. Adds libc for the group-kill syscall and three regression tests covering direct-child kill, grandchild reaping via the group, and the disarmed no-kill path. Refs #53 * fix(review): reap-then-disarm on serve-path errors; tini/comment nits Address code-review findings on the #53 fix: - run_git_service no longer early-returns on a stdin-write error. It captures the write result, always reaps the child, then disarms the group guard before surfacing the error. Previously a write/wait error path could drop the still-armed guard after the child was already reaped, so the group SIGKILL could in theory land on a reused pgid. (correctness, reliability, adversarial all flagged this region.) - Drop tini's -g flag: the node manages its own children and graceful shutdown, so group-wide signalling would only disturb in-flight git helpers on shutdown. - Correct the SAFETY comment (kill(2) is not relevant to async-signal-safety here) and the alive() test-helper comment (EPERM does not read as alive). * fix(node): SIGTERM (not SIGKILL) the served-git group on disconnect SIGKILL gave git no chance to run its signal cleanup, so an aborted receive-pack could leave a stale .git/*.lock that blocks the next push. SIGTERM lets git remove its lock files before exiting. Signalling the whole process group still reaches pack-objects directly, so the grandchild is terminated rather than orphaned, and a single immediate signal avoids any delayed-kill pid-reuse window. Refs #53 * docs(node): correct stale SIGKILL comments to SIGTERM in served-git teardown
68 lines
2.8 KiB
YAML
68 lines
2.8 KiB
YAML
# Run a gitlawb node + Postgres locally. For on-chain PoS operation, supply
|
|
# the operator key + contract addresses via a .env file or shell environment.
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
environment:
|
|
POSTGRES_DB: gitlawb
|
|
POSTGRES_USER: gitlawb
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme}
|
|
volumes:
|
|
- pg-data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U gitlawb"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
restart: unless-stopped
|
|
|
|
node:
|
|
build: .
|
|
# Reap reparented orphan processes so git's grandchildren (e.g. pack-objects
|
|
# left behind when a served clone disconnects) can't accumulate as zombies
|
|
# and exhaust the PID table (#53). The image also runs under tini, so this is
|
|
# belt-and-suspenders for the quickstart.
|
|
init: true
|
|
# Cap the process table so a regression fails loudly instead of taking the
|
|
# host down. Sits well above normal concurrent git fan-out.
|
|
pids_limit: 1024
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
ports:
|
|
- "${GITLAWB_PORT:-7545}:${GITLAWB_PORT:-7545}" # HTTP API + git smart-HTTP
|
|
- "${GITLAWB_P2P_PORT:-7546}:${GITLAWB_P2P_PORT:-7546}/udp" # libp2p QUIC
|
|
volumes:
|
|
- gitlawb-data:/data
|
|
environment:
|
|
DATABASE_URL: postgresql://gitlawb:${POSTGRES_PASSWORD:-changeme}@postgres:5432/gitlawb
|
|
GITLAWB_HOST: 0.0.0.0
|
|
GITLAWB_PORT: ${GITLAWB_PORT:-7545}
|
|
GITLAWB_PUBLIC_URL: ${GITLAWB_PUBLIC_URL:-http://localhost:7545}
|
|
GITLAWB_P2P_PORT: ${GITLAWB_P2P_PORT:-7546}
|
|
GITLAWB_BOOTSTRAP_PEERS: ${GITLAWB_BOOTSTRAP_PEERS:-}
|
|
GITLAWB_BOOTSTRAP_DISABLE_SEEDS: ${GITLAWB_BOOTSTRAP_DISABLE_SEEDS:-false}
|
|
GITLAWB_REQUIRE_SIGNED_PEER_WRITES: ${GITLAWB_REQUIRE_SIGNED_PEER_WRITES:-false}
|
|
GITLAWB_P2P_BOOTSTRAP: ${GITLAWB_P2P_BOOTSTRAP:-}
|
|
GITLAWB_PUBLIC_READ: ${GITLAWB_PUBLIC_READ:-true}
|
|
GITLAWB_MAX_PACK_BYTES: ${GITLAWB_MAX_PACK_BYTES:-2147483648}
|
|
# Sync
|
|
GITLAWB_AUTO_SYNC: ${GITLAWB_AUTO_SYNC:-false}
|
|
# On-chain PoS (optional — leave unset for local/dev)
|
|
GITLAWB_CHAIN_RPC_URL: ${GITLAWB_CHAIN_RPC_URL:-}
|
|
GITLAWB_CONTRACT_NODE_STAKING: ${GITLAWB_CONTRACT_NODE_STAKING:-}
|
|
GITLAWB_OPERATOR_PRIVATE_KEY: ${GITLAWB_OPERATOR_PRIVATE_KEY:-}
|
|
GITLAWB_OPERATOR_STRICT_MODE: ${GITLAWB_OPERATOR_STRICT_MODE:-false}
|
|
GITLAWB_HEARTBEAT_INTERVAL_HOURS: ${GITLAWB_HEARTBEAT_INTERVAL_HOURS:-20}
|
|
# Optional shared storage (leave unset to use local disk only)
|
|
GITLAWB_TIGRIS_BUCKET: ${GITLAWB_TIGRIS_BUCKET:-}
|
|
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-}
|
|
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-}
|
|
AWS_ENDPOINT_URL_S3: ${AWS_ENDPOINT_URL_S3:-}
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
pg-data:
|
|
gitlawb-data:
|