mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-01 10:11:30 +08:00
Add docs/source/companion.rst: what the feature is, why/when to use it, quick start, per-companion options, states, runtime control via the socket and gunicorn-companion CLI, reload/shutdown behavior, and limitations. Wire it into the toctree and the feature list on the index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
207 lines
7.5 KiB
ReStructuredText
207 lines
7.5 KiB
ReStructuredText
.. _companion:
|
|
|
|
===================
|
|
Companion Processes
|
|
===================
|
|
|
|
Most real deployments run more than HTTP workers. Alongside the web server you
|
|
often have background processes: task queues (RQ, Celery), a scheduler, a
|
|
websocket / socket.io server, or custom daemons. Normally these are started and
|
|
supervised separately with systemd or supervisor.
|
|
|
|
The **companion process manager** lets Gunicorn run those processes for you, as
|
|
children of the same master. They get the same lifecycle as your web workers
|
|
and, when you use :ref:`preload-app`, they share the preloaded application
|
|
memory through copy-on-write.
|
|
|
|
Why use it
|
|
==========
|
|
|
|
- **One thing to run.** Web workers and background processes start, stop, and
|
|
reload together under a single Gunicorn command.
|
|
- **Less memory.** With ``--preload`` the application is loaded once in the
|
|
master; companions fork from it and share that memory instead of each loading
|
|
their own copy.
|
|
- **No drift.** There is one place that owns the lifecycle, so background
|
|
processes don't get out of step with the web workers.
|
|
|
|
If you only run HTTP workers, you don't need this feature and can ignore it.
|
|
|
|
How it works
|
|
============
|
|
|
|
Gunicorn forks **one** extra child after preload: the *companion manager*. The
|
|
manager forks and supervises each companion you configured. The arbiter only
|
|
watches the single manager; the manager handles everything below it.
|
|
|
|
.. code-block:: text
|
|
|
|
gunicorn master (preloaded app)
|
|
├── HTTP worker
|
|
├── HTTP worker
|
|
└── companion manager
|
|
├── rq-default
|
|
├── scheduler
|
|
└── socketio
|
|
|
|
Each companion is just a Python callable you point Gunicorn at. The manager
|
|
forks a fresh process, runs the callable, and keeps it alive: if it crashes, the
|
|
manager restarts it after a short delay.
|
|
|
|
Quick start
|
|
===========
|
|
|
|
A companion is configured in your normal Gunicorn config file (the one you pass
|
|
with ``-c``). Each entry needs a ``name`` and a ``target``. The target is a
|
|
``"module:callable"`` string; the callable takes no arguments and runs the
|
|
process (it is expected to block, like a worker's main loop).
|
|
|
|
.. code-block:: python
|
|
|
|
# gunicorn.conf.py
|
|
preload_app = True # required to share memory with companions
|
|
|
|
companion_workers = [
|
|
{"name": "scheduler", "target": "myapp.tasks:run_scheduler"},
|
|
{"name": "rq-default", "target": "myapp.tasks:run_rq", "env": {"QUEUE": "default"}},
|
|
]
|
|
|
|
Run Gunicorn as usual::
|
|
|
|
gunicorn -c gunicorn.conf.py --preload myapp:application
|
|
|
|
You'll see the companion manager and each companion start in the logs.
|
|
|
|
Per-companion options
|
|
---------------------
|
|
|
|
Each entry in ``companion_workers`` may set these keys in addition to ``name``
|
|
and ``target``:
|
|
|
|
.. list-table::
|
|
:header-rows: 1
|
|
:widths: 20 80
|
|
|
|
* - Key
|
|
- Meaning
|
|
* - ``cwd``
|
|
- Directory to change into before running the target.
|
|
* - ``env``
|
|
- Extra environment variables, merged onto the inherited env.
|
|
* - ``stop_signal``
|
|
- Signal sent to ask the companion to stop (default ``SIGTERM``).
|
|
* - ``stop_timeout``
|
|
- Seconds to wait after the stop signal before ``SIGKILL``.
|
|
* - ``reload_timeout``
|
|
- Seconds to wait for the old process to exit on restart.
|
|
* - ``startsecs``
|
|
- Seconds a companion must stay up to count as started.
|
|
* - ``stdout``
|
|
- File path for stdout, or ``"inherit"`` (the default).
|
|
* - ``stderr``
|
|
- File path, ``"stdout"`` to merge with stdout, or ``"inherit"``.
|
|
|
|
Any key you leave out falls back to the matching global setting
|
|
(``companion_stop_signal``, ``companion_stop_timeout``, and so on), so you can
|
|
set a default once and override it per companion.
|
|
|
|
Keeping companions in a separate file
|
|
--------------------------------------
|
|
|
|
If you want to change companion specs without touching your web config, put the
|
|
``companion_*`` settings in their own Python file and point Gunicorn at it::
|
|
|
|
companion_config_file = "/etc/gunicorn/companions.py"
|
|
|
|
The manager reads its companion settings from that file instead of the main
|
|
config.
|
|
|
|
States
|
|
======
|
|
|
|
A companion is always in one of these states (the same vocabulary as
|
|
``supervisorctl``):
|
|
|
|
.. list-table::
|
|
:header-rows: 1
|
|
:widths: 20 80
|
|
|
|
* - State
|
|
- Meaning
|
|
* - ``STARTING``
|
|
- Just forked, not yet past ``startsecs``.
|
|
* - ``RUNNING``
|
|
- Up and healthy.
|
|
* - ``BACKOFF``
|
|
- Crashed; waiting ``restart_delay`` seconds before retrying.
|
|
* - ``STOPPING``
|
|
- Was asked to stop; draining before exit.
|
|
* - ``STOPPED``
|
|
- Stopped on purpose and will not auto-restart.
|
|
|
|
A companion that exits on its own goes to ``BACKOFF`` and is restarted. One you
|
|
stop by hand stays ``STOPPED`` until you start it again.
|
|
|
|
Controlling companions at runtime
|
|
==================================
|
|
|
|
Set a control socket and you can inspect and steer companions while Gunicorn
|
|
runs::
|
|
|
|
companion_control_socket = "/run/gunicorn/companion.sock"
|
|
|
|
A small CLI, ``gunicorn-companion``, talks to it::
|
|
|
|
gunicorn-companion -s /run/gunicorn/companion.sock status
|
|
gunicorn-companion -s /run/gunicorn/companion.sock restart scheduler
|
|
gunicorn-companion -s /run/gunicorn/companion.sock stop rq-default
|
|
gunicorn-companion -s /run/gunicorn/companion.sock start rq-default
|
|
|
|
You can also set ``GUNICORN_COMPANION_SOCKET`` instead of passing ``-s`` every
|
|
time. The protocol is plain newline-delimited JSON, so ``socat`` works too::
|
|
|
|
echo '{"cmd": "status"}' | socat - UNIX-CONNECT:/run/gunicorn/companion.sock
|
|
|
|
Commands:
|
|
|
|
- ``status`` — show every companion's state.
|
|
- ``start <name>`` / ``stop <name>`` / ``restart <name>`` — act on one.
|
|
- ``reread`` — re-read the config file and apply only what changed: new
|
|
companions start, removed ones stop, changed ones restart, untouched ones are
|
|
left alone. It is transactional — if the new config is invalid, nothing
|
|
changes and the old one keeps running.
|
|
|
|
The socket is created mode ``0o600`` (owner only). Change it with
|
|
``companion_control_socket_mode`` if you need group access.
|
|
|
|
Reload and shutdown
|
|
===================
|
|
|
|
**Reload (SIGHUP).** A reload recycles your HTTP workers and re-reads config.
|
|
The companion manager is restarted **only if the companion config actually
|
|
changed** — an ordinary web reload leaves your companions running untouched, so
|
|
it stays fast. Note that, just like HTTP workers under ``--preload``, companions
|
|
pick up new *application code* only on a full restart, not on ``SIGHUP``. For
|
|
fine-grained changes without a full reload, use the ``reread`` command.
|
|
|
|
**Shutdown (SIGTERM).** Gunicorn asks the manager to stop, which sends each
|
|
companion its ``stop_signal`` and waits up to ``stop_timeout`` before forcing it
|
|
down with ``SIGKILL``. Gunicorn gives the manager enough time to drain all its
|
|
companions before it gives up; tune that with
|
|
``companion_manager_stop_timeout`` (or it is derived from the slowest companion
|
|
plus ``companion_manager_shutdown_buffer``).
|
|
|
|
Limitations
|
|
===========
|
|
|
|
- **Hot upgrade (USR2) is not supported with companions.** During a ``USR2``
|
|
upgrade the old and new masters run side by side, so each runs its own
|
|
companion manager and every companion runs twice — bad for singletons like a
|
|
scheduler. Restart the master instead of using ``USR2`` when companions are
|
|
configured, or keep singletons out of the companion set. A ``SIGHUP`` reload
|
|
is fine.
|
|
- **Linux is the primary target.** Orphan cleanup uses ``prctl`` on Linux, with
|
|
a portable parent-watch fallback elsewhere.
|
|
|
|
See the :ref:`settings` page for every ``companion_*`` option.
|