Skip to content

Latest commit

 

History

History
287 lines (213 loc) · 9.05 KB

File metadata and controls

287 lines (213 loc) · 9.05 KB

CLI Command-Line Interface

The server_runner binary provides a production entry point for running, managing, and inspecting the server.

Quick Start

# Build the server
make server

# Start with default config
\./server_runner start

# Start with custom config and port
\./server_runner start -c config/server.example.json -p 9090

# Check if the server is running
\./server_runner status

# Graceful shutdown
\./server_runner stop

Usage

Usage: server_runner <command> [options]

Commands:
  start       Start the server (foreground, or -d for daemon)
  stop        Stop a running server
  reload      Reload configuration (daemon mode; shuts down foreground)
  status      Check server status
  validate    Validate configuration
  config      Show effective configuration
  version     Show version information
  help        Show this help

Start options:
  -c, --config <file>         Config file (default: config/server.json)
  -p, --port <port>           Override bind port (0-65535, 0=ephemeral)
  -H, --host <address>        Override bind address (numeric IPv4 only)
  -l, --log-level <level>     Override log level
                              (trace, debug, info, warn, error, critical)
  -w, --workers <N>           Override worker thread count (0 = auto)
  -P, --pid-file <file>       PID file path (default: /tmp/reactor_server.pid)
  -d, --daemonize             Run as a background daemon
  --no-health-endpoint       Disable /health and /stats endpoints

Stop/status/reload options:
  -P, --pid-file <file>       PID file path (default: /tmp/reactor_server.pid)

Validate/config options:
  -c, --config <file>         Config file
  -p, --port <port>           Override bind port
  -H, --host <address>        Override bind address
  -l, --log-level <level>     Override log level
  -w, --workers <N>           Override worker threads
  -d, --daemonize             Check daemon-mode constraints (validate only)
  -P, --pid-file <file>       PID file to validate (validate -d only)

Global options:
  -v, --version               Same as 'version'
  -V, --version-verbose       Verbose version with build details
  -h, --help                  Same as 'help'

Running \./server_runner with no arguments prints the usage summary.

Config Override Precedence

Values are resolved in this order (highest wins):

4. CLI flags      (-p 9090, -H 0.0.0.0, -l debug, -w 4)
3. Environment    (REACTOR_BIND_PORT=9090)
2. Config file    (config/server.example.json: {"bind_port": 9090})
1. Defaults       (ServerConfig{} defaults: bind_port=8080)

Config Validation

Validate a configuration file without starting the server:

\./server_runner validate -c config/server.example.json
# Output: "Configuration is valid." (exit 0) or error (exit 1)

Effective Config Dump

Show the fully resolved config (after applying file, env, and CLI overrides):

\./server_runner config -p 9090 -l debug

This outputs formatted JSON that can be redirected to a file and used as a config:

\./server_runner config -p 9090 > my_config.json
\./server_runner start -c my_config.json

Server Management

Start

\./server_runner start
\./server_runner start -p 9090 -l debug
\./server_runner start -c config/server.example.json --no-health-endpoint

Status Check

\./server_runner status
# reactor_server is running
#   PID:        12345
#   PID file:   /tmp/reactor_server.pid

Daemon Mode

Run the server as a background daemon:

# Requires a log file (daemon has no terminal)
\./server_runner start -d -c config/production.json

# Or set log file via environment variable
REACTOR_LOG_FILE=/var/log/reactor.log \./server_runner start -d

# Verify it started
\./server_runner status

Daemon mode requirements:

  • A log file must be configured (log.file in config or REACTOR_LOG_FILE env var)
  • Log file, PID file, and TLS cert/key paths must be absolute
  • The launching shell sees exit code 0 once the daemon is ready (readiness pipe), or exit code 1 on startup failure

Graceful Stop

\./server_runner stop
# Sent SIGTERM to reactor_server (PID 12345)

Configuration Reload

Reload the configuration of a running daemon without restarting:

\./server_runner reload
# Sent SIGHUP to reactor_server (PID 12345)

Reload-safe fields (applied immediately or to new connections):

  • log.level, log.file, log.max_file_size, log.max_files
  • idle_timeout_sec, request_timeout_sec
  • max_connections, max_body_size, max_header_size, max_ws_message_size
  • shutdown_drain_timeout_sec
  • http2.max_concurrent_streams, http2.initial_window_size, http2.max_frame_size, http2.max_header_list_size

Restart-required fields (logged as skipped on reload):

  • bind_host, bind_port, tls.*, worker_threads, http2.enabled

You can also send SIGHUP directly:

kill -HUP $(cat /tmp/reactor_server.pid)

Note: If a foreground server was started under nohup, SIGHUP is inherited as SIG_IGN and the reload command will be silently ignored. Use daemon mode (-d) for reliable SIGHUP-based reload.

Signal Handling

Signal Behavior
SIGTERM Graceful shutdown (sends WS Close 1001, drains connections, exits)
SIGINT Same as SIGTERM (Ctrl+C in foreground)
SIGHUP Daemon: reload configuration + reopen log files. Foreground: graceful shutdown (terminal hangup)
SIGPIPE Ignored (handled by MSG_NOSIGNAL)

Signal handling uses sigwait() (POSIX synchronous signal wait). Signals are blocked in all threads via pthread_sigmask; the main thread loops on sigwait(). In daemon mode, SIGHUP triggers a full configuration reload (re-reads config file, validates, applies reload-safe fields, reopens log files); in foreground mode, SIGHUP causes graceful shutdown (standard Unix terminal hangup behavior). SIGTERM/SIGINT always trigger shutdown.

Log Rotation

The server supports logrotate-style log rotation via SIGHUP:

# Manual rotation
kill -HUP $(cat /tmp/reactor_server.pid)

# logrotate config example (/etc/logrotate.d/reactor_server):
# /var/log/reactor.log {
#     daily
#     rotate 7
#     postrotate
#         kill -HUP $(cat /tmp/reactor_server.pid) 2>/dev/null || true
#     endscript
# }

Note: By default (max_files > 1), the server uses date-based log file naming (reactor-YYYY-MM-DD[-N].log) with automatic size-based rotation. When using external logrotate, set log.max_files to 1 in the config to use the raw file path with no automatic rotation — fully compatible with logrotate's rename + SIGHUP workflow.

PID File

The server writes its PID to a file on startup and removes it on exit. The PID file uses flock() for race-free singleton enforcement.

  • Default path: /tmp/reactor_server.pid
  • Override: -P /path/to/custom.pid
  • If the server crashes (SIGKILL), the stale PID file is automatically detected on the next start

Multiple Instances

Run multiple instances with different PID files and ports:

\./server_runner start -p 8080 -P /tmp/reactor_8080.pid &
\./server_runner start -p 8081 -P /tmp/reactor_8081.pid &

Health & Stats Endpoints

By default, the server registers /health and /stats endpoints:

curl http://127.0.0.1:8080/health
# {"status":"ok","pid":12345,"uptime_seconds":3600}

curl http://127.0.0.1:8080/stats
# {
#   "uptime_seconds": 3600,
#   "connections": {
#     "active": 42, "active_http1": 30, "active_http2": 12,
#     "active_h2_streams": 58, "total_accepted": 10234
#   },
#   "requests": { "total": 50000, "active": 15 },
#   "config": {
#     "bind_host": "127.0.0.1", "bind_port": 8080,
#     "worker_threads": 3, "max_connections": 10000,
#     "idle_timeout_sec": 300, "request_timeout_sec": 30,
#     "tls_enabled": false, "http2_enabled": true
#   }
# }
  • /health — lightweight liveness check with PID and uptime
  • /stats — runtime metrics with connection/request counters and current config
  • The config section in /stats reflects live values for reload-safe fields (max_connections, idle_timeout_sec, request_timeout_sec) and startup values for restart-required fields
  • No PID, file paths, or TLS details are exposed in /stats
  • If the server is internet-facing, restrict access to these endpoints via firewall or reverse proxy

Disable both with --no-health-endpoint.

Version Info

\./server_runner version
# reactor_server version 1.0.0

\./server_runner version -V
# reactor_server version 1.0.0
#   Compiler:  13.3.0 (C++17)
#   OpenSSL:   OpenSSL 3.0.13 30 Jan 2024
#   Platform:  Linux
#   Features:  HTTP/1.1, HTTP/2 (RFC 9113), WebSocket (RFC 6455), TLS/SSL

Exit Codes

Code Meaning
0 Success (normal exit, config valid, status confirms running, stop sent)
1 General error (config invalid, bind failure, server not running)
2 Usage error (unknown command, invalid option)

Build

make server         # Build only the production binary
make all            # Build both test runner (./run) and server (\./server_runner)
make clean          # Remove both binaries