From 3e60d2942d62347761bed51e87f4d919a5f8cfbc Mon Sep 17 00:00:00 2001 From: Benoit Chesneau Date: Fri, 13 Feb 2026 02:29:44 +0100 Subject: [PATCH] docs: add gunicornc control interface guide - Add guides/gunicornc.md with usage examples and command reference - Update mkdocs.yml navigation to include Control Interface guide - Update 2026-news.md and news.md changelog with 25.2.0 release - Regenerate reference/settings.md with control socket settings --- docs/content/2026-news.md | 17 ++ docs/content/guides/gunicornc.md | 306 +++++++++++++++++++++++++++++ docs/content/news.md | 17 ++ docs/content/reference/settings.md | 47 +++++ mkdocs.yml | 1 + 5 files changed, 388 insertions(+) create mode 100644 docs/content/guides/gunicornc.md diff --git a/docs/content/2026-news.md b/docs/content/2026-news.md index 59a3dcd6..56476e9c 100644 --- a/docs/content/2026-news.md +++ b/docs/content/2026-news.md @@ -1,6 +1,23 @@ # Changelog - 2026 +## 25.2.0 - 2026-02-13 + +### New Features + +- **Control Interface (gunicornc)**: Add interactive control interface for managing + running Gunicorn instances, similar to birdc for BIRD routing daemon + - Unix socket-based communication with JSON protocol + - Interactive mode with readline support and command history + - Commands: `show all/workers/dirty/config/stats/listeners` + - Worker management: `worker add/remove/kill`, `dirty add/remove` + - Server control: `reload`, `reopen`, `shutdown` + - New settings: `--control-socket`, `--control-socket-mode`, `--no-control-socket` + - New CLI tool: `gunicornc` for connecting to control socket + - See [Control Interface Guide](guides/gunicornc.md) for details + +--- + ## 25.1.0 - 2026-02-12 ### New Features diff --git a/docs/content/guides/gunicornc.md b/docs/content/guides/gunicornc.md new file mode 100644 index 00000000..012f0791 --- /dev/null +++ b/docs/content/guides/gunicornc.md @@ -0,0 +1,306 @@ +--- +title: Control Interface (gunicornc) +menu: + guides: + weight: 15 +--- + +# Control Interface (gunicornc) + +Gunicorn provides a control interface similar to [birdc](https://bird.network.cz/?get_doc&v=20&f=bird-3.html) for the BIRD routing daemon. This allows you to inspect and manage a running Gunicorn instance via a Unix socket. + +## Overview + +The control interface consists of two parts: + +1. **Control Socket Server** - Runs in the arbiter process, accepts commands via Unix socket +2. **gunicornc CLI** - Interactive client that connects to the control socket + +## Quick Start + +### Start Gunicorn with Control Socket + +By default, Gunicorn creates a control socket at `gunicorn.ctl` in the current directory: + +```bash +gunicorn -w 4 myapp:app +``` + +Or specify a custom path: + +```bash +gunicorn --control-socket /tmp/myapp.ctl -w 4 myapp:app +``` + +### Connect with gunicornc + +```bash +# Connect to default socket (./gunicorn.ctl) +gunicornc + +# Connect to custom socket +gunicornc -s /tmp/myapp.ctl + +# Run a single command +gunicornc -c "show workers" + +# Output as JSON (for scripting) +gunicornc -c "show stats" -j +``` + +## Interactive Mode + +When run without the `-c` flag, gunicornc enters interactive mode with readline support: + +``` +$ gunicornc +Connected to gunicorn.ctl +Type 'help' for available commands, 'quit' to exit. + +gunicorn> show workers +PID AGE BOOTED LAST_BEAT +---------------------------------------- +12345 1 yes 0.2s ago +12346 2 yes 0.1s ago +12347 3 yes 0.3s ago + +Total: 3 workers + +gunicorn> worker add 2 +{ + "added": 2, + "previous": 3, + "total": 5 +} + +gunicorn> quit +``` + +## Commands + +### Show Commands + +| Command | Description | +|---------|-------------| +| `show all` | Overview of all processes (arbiter, web workers, dirty workers) | +| `show workers` | List HTTP workers with status | +| `show dirty` | List dirty workers and apps | +| `show config` | Show current effective configuration | +| `show stats` | Show server statistics | +| `show listeners` | Show bound sockets | +| `help` | Show available commands | + +### Worker Management + +| Command | Description | +|---------|-------------| +| `worker add [N]` | Spawn N workers (default 1) | +| `worker remove [N]` | Remove N workers (default 1) | +| `worker kill ` | Gracefully terminate specific worker | + +### Dirty Worker Management + +| Command | Description | +|---------|-------------| +| `dirty add [N]` | Spawn N dirty workers (default 1) | +| `dirty remove [N]` | Remove N dirty workers (default 1) | + +!!! note "Per-App Worker Limits" + When using `dirty add`, workers only load apps that haven't reached their + worker limits. If all apps are at their limits, no new workers will be spawned. + The response will include a `reason` field explaining this. + +### Server Control + +| Command | Description | +|---------|-------------| +| `reload` | Graceful reload (equivalent to SIGHUP) | +| `reopen` | Reopen log files (equivalent to SIGUSR1) | +| `shutdown [graceful\|quick]` | Shutdown server (SIGTERM or SIGINT) | + +## Example Session + +``` +$ gunicornc +Connected to gunicorn.ctl +Type 'help' for available commands, 'quit' to exit. + +gunicorn> show all +ARBITER (master) + PID: 12345 + +WEB WORKERS (4) + PID AGE BOOTED LAST_BEAT + -------------------------------------- + 12346 1 yes 0.05s ago + 12347 2 yes 0.04s ago + 12348 3 yes 0.03s ago + 12349 4 yes 0.02s ago + +DIRTY ARBITER + PID: 12350 + +DIRTY WORKERS (2) + PID AGE APPS + -------------------------------------------------- + 12351 1 MLModel + ImageProcessor + 12352 2 MLModel + +gunicorn> show stats +Uptime: 2h 15m 30s +PID: 12345 +Workers current: 4 +Workers target: 4 +Workers spawned: 6 +Workers killed: 2 +Reloads: 1 + +gunicorn> worker add +{ + "added": 1, + "previous": 4, + "total": 5 +} + +gunicorn> dirty add 1 +{ + "success": true, + "operation": "add", + "requested": 1, + "spawned": 1, + "total_workers": 3, + "target_workers": 3 +} + +gunicorn> quit +``` + +## Configuration + +### Settings + +| Setting | CLI Flag | Default | Description | +|---------|----------|---------|-------------| +| `control_socket` | `--control-socket` | `gunicorn.ctl` | Unix socket path | +| `control_socket_mode` | `--control-socket-mode` | `0o600` | Socket file permissions | +| `control_socket_disable` | `--no-control-socket` | `False` | Disable control socket | + +### Example Configuration + +```python +# gunicorn.conf.py +bind = "0.0.0.0:8000" +workers = 4 + +# Control socket settings +control_socket = "/var/run/gunicorn/myapp.ctl" +control_socket_mode = 0o660 # Allow group access +``` + +## Scripting + +Use the `-j` flag for JSON output when scripting: + +```bash +#!/bin/bash + +# Get current worker count +workers=$(gunicornc -c "show stats" -j | jq -r '.workers_current') +echo "Current workers: $workers" + +# Scale up if needed +if [ "$workers" -lt 8 ]; then + gunicornc -c "worker add $((8 - workers))" +fi +``` + +## Security + +The control socket uses filesystem permissions for access control: + +- **Default mode**: `0o600` (owner only) +- **No authentication**: Relies on filesystem permissions +- **Unix socket only**: No TCP/remote access + +To allow group access: + +```python +control_socket_mode = 0o660 +``` + +To disable the control socket entirely: + +```bash +gunicorn --no-control-socket myapp:app +``` + +## Protocol + +The control interface uses a JSON-based protocol with length-prefixed framing: + +``` ++----------------+------------------+ +| Length (4B BE) | JSON Payload | ++----------------+------------------+ +``` + +### Request Format + +```json +{ + "id": 1, + "command": "show workers" +} +``` + +### Response Format + +```json +{ + "id": 1, + "status": "ok", + "data": { ... } +} +``` + +### Error Response + +```json +{ + "id": 1, + "status": "error", + "error": "Unknown command: foo" +} +``` + +## Troubleshooting + +### Cannot connect to socket + +``` +Error: Connection refused +``` + +- Check that Gunicorn is running +- Verify the socket path is correct +- Check socket file permissions + +### Permission denied + +``` +Error: Permission denied +``` + +- Check that you have read/write access to the socket file +- The socket is created with mode `0o600` by default (owner only) + +### Socket not found + +``` +Error: No such file or directory +``` + +- Gunicorn creates the socket relative to the working directory by default +- Use an absolute path with `--control-socket /path/to/socket.ctl` +- Check if `--no-control-socket` was specified diff --git a/docs/content/news.md b/docs/content/news.md index 8125086e..15592160 100644 --- a/docs/content/news.md +++ b/docs/content/news.md @@ -1,6 +1,23 @@ # Changelog +## 25.2.0 - 2026-02-13 + +### New Features + +- **Control Interface (gunicornc)**: Add interactive control interface for managing + running Gunicorn instances, similar to birdc for BIRD routing daemon + - Unix socket-based communication with JSON protocol + - Interactive mode with readline support and command history + - Commands: `show all/workers/dirty/config/stats/listeners` + - Worker management: `worker add/remove/kill`, `dirty add/remove` + - Server control: `reload`, `reopen`, `shutdown` + - New settings: `--control-socket`, `--control-socket-mode`, `--no-control-socket` + - New CLI tool: `gunicornc` for connecting to control socket + - See [Control Interface Guide](guides/gunicornc.md) for details + +--- + ## 25.1.0 - 2026-02-12 ### New Features diff --git a/docs/content/reference/settings.md b/docs/content/reference/settings.md index 18023593..bd9aaa3f 100644 --- a/docs/content/reference/settings.md +++ b/docs/content/reference/settings.md @@ -48,6 +48,53 @@ A WSGI application path in pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. !!! info "Added in 20.1.0" +## Control + +### `control_socket` + +**Command line:** `--control-socket PATH` + +**Default:** `'gunicorn.ctl'` + +Unix socket path for control interface. + +The control socket allows runtime management of Gunicorn via the +``gunicornc`` command-line tool. Commands include viewing worker +status, adjusting worker count, and graceful reload/shutdown. + +By default, creates ``gunicorn.ctl`` in the working directory. +Set an absolute path for a fixed location (e.g., ``/var/run/gunicorn.ctl``). + +Use ``--no-control-socket`` to disable. + +!!! info "Added in 25.1.0" + +### `control_socket_mode` + +**Command line:** `--control-socket-mode INT` + +**Default:** `384` + +Permission mode for control socket. + +Restricts who can connect to the control socket. Default ``0600`` +allows only the socket owner. Set to ``0660`` to allow group access. + +!!! info "Added in 25.1.0" + +### `control_socket_disable` + +**Command line:** `--no-control-socket` + +**Default:** `False` + +Disable control socket. + +When set, no control socket is created and ``gunicornc`` cannot +connect to this Gunicorn instance. + +!!! info "Added in 25.1.0" + ## Debugging ### `reload` diff --git a/mkdocs.yml b/mkdocs.yml index 03193260..f1c935f4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -18,6 +18,7 @@ nav: - HTTP/2: guides/http2.md - ASGI Worker: asgi.md - Dirty Arbiters: dirty.md + - Control Interface: guides/gunicornc.md - uWSGI Protocol: uwsgi.md - Signals: signals.md - Instrumentation: instrumentation.md