Skip to content

feat(ctl): add gunicornc control interface#3505

Merged
benoitc merged 13 commits intomasterfrom
feature/gunicornc-control-interface
Feb 13, 2026
Merged

feat(ctl): add gunicornc control interface#3505
benoitc merged 13 commits intomasterfrom
feature/gunicornc-control-interface

Conversation

@benoitc
Copy link
Owner

@benoitc benoitc commented Feb 13, 2026

Summary

  • Add control socket server running in arbiter process for runtime management
  • Add gunicornc CLI client with interactive and single-command modes
  • JSON protocol with length-prefixed framing for communication
  • Commands: show workers/stats/config/listeners/dirty, worker add/remove/kill, dirty add/remove, reload, reopen, shutdown
  • Stats tracking (uptime, workers spawned/killed, reloads)
  • New config options: control_socket, control_socket_mode, --no-control-socket

Example usage

# Start gunicorn (creates ./gunicorn.ctl by default)
gunicorn -w 4 myapp:app

# Interactive mode
gunicornc
gunicorn> show workers
gunicorn> worker add 2
gunicorn> quit

# Single command mode
gunicornc -c "show workers"
gunicornc -c "show stats" -j  # JSON output

@benoitc benoitc force-pushed the feature/gunicornc-control-interface branch from 9def1d2 to 887abaf Compare February 13, 2026 00:30
Add a control socket server and CLI client for runtime management
of Gunicorn instances, similar to birdc for BIRD routing daemon.

Features:
- Control socket server running in arbiter process (asyncio/threaded)
- gunicornc CLI with interactive and single-command modes
- JSON protocol with length-prefixed framing
- Commands: show workers/stats/config/listeners/dirty, worker add/remove/kill,
  dirty add/remove, reload, reopen, shutdown
- Stats tracking (uptime, workers spawned/killed, reloads)
- Configurable socket path and permissions

New config options:
- control_socket: Unix socket path (default: gunicorn.ctl)
- control_socket_mode: Socket permissions (default: 0o600)
- --no-control-socket: Disable control socket
@benoitc benoitc force-pushed the feature/gunicornc-control-interface branch from 887abaf to a57507c Compare February 13, 2026 00:38
Change 'No apps need more workers' from warning to debug level
to avoid log spam when all apps have sufficient workers.
Displays complete hierarchy: arbiter PID, web workers with their
PIDs/status, dirty arbiter PID, and dirty workers with their apps.
Add MSG_TYPE_STATUS to dirty protocol to allow querying the dirty
arbiter for its workers. The control socket now connects to the
dirty arbiter socket to retrieve worker information.
- Add encode_status method to BinaryProtocol
- Use arbiter.dirty_arbiter.socket_path instead of env var when available
The dirty protocol response uses 'result' not 'data' for the payload.
Replace signal-based dirty add/remove with protocol messages:
- Add MSG_TYPE_MANAGE to dirty protocol for worker management
- Add MANAGE_OP_ADD and MANAGE_OP_REMOVE operation codes
- Add handle_manage_request() in DirtyArbiter
- Update handlers to send messages instead of SIGTTIN/SIGTTOU signals

New workers only load apps that haven't reached their worker limits.
When all apps are at their limits, returns reason in response.
Only increment num_workers when a worker is actually spawned.
- 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
- Use preexec_fn=os.setsid to create new process group
- Send signals to process group with os.killpg() instead of single process
- Add explicit timeout and graceful-timeout to gunicorn command
- Fixes test failures on PyPy 3.10 where signals weren't propagating properly
@benoitc benoitc merged commit 730350e into master Feb 13, 2026
27 checks passed
@benoitc benoitc deleted the feature/gunicornc-control-interface branch February 13, 2026 10:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant