gunicorn/examples/dirty_example/gunicorn_conf.py
Benoit Chesneau 709a6ad159
feat(dirty): add stash - global shared state between workers (#3503)
* feat(dirty): add stash - global shared state between workers

Add a simple key-value store (stash) that allows dirty workers to share
state through the arbiter. Tables are stored directly in arbiter memory
for fast access and simplicity.

Features:
- Auto-create tables on first access
- Dict-like interface via stash.table()
- Pattern matching for keys (glob patterns)
- Module-level API: stash.put(), stash.get(), stash.delete(), etc.

Usage:
    from gunicorn.dirty import stash

    stash.put("sessions", "user:1", {"name": "Alice"})
    user = stash.get("sessions", "user:1")

    # Or dict-like
    sessions = stash.table("sessions")
    sessions["user:1"] = {"name": "Alice"}

New files:
- gunicorn/dirty/stash.py - Client API and StashTable class
- Protocol additions for MSG_TYPE_STASH and STASH_OP_* codes

Note: Tables are ephemeral - lost if arbiter restarts.

* test(dirty): add tests for stash protocol and encoding

Test coverage for:
- Stash message creation and encoding
- Protocol constants (MSG_TYPE_STASH, STASH_OP_*)
- Error classes (StashError, StashTableNotFoundError, StashKeyNotFoundError)
- StashTable dict-like interface
- Edge cases: unicode, complex values, special patterns

* example(dirty): add stash usage example and integration tests

- Add SessionApp to dirty_app.py demonstrating stash usage
- Add /session/* endpoints to wsgi_app.py
- Add test_stash_integration.py with Docker tests
- Update docker-compose.yml with stash-test service
- Fix: Set GUNICORN_DIRTY_SOCKET in dirty arbiter for worker access

* docs(dirty): add stash documentation
2026-02-12 21:45:49 +01:00

63 lines
1.4 KiB
Python

#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
"""
Gunicorn configuration for Dirty Workers Example
Run with:
cd examples/dirty_example
gunicorn wsgi_app:app -c gunicorn_conf.py
"""
# Basic settings
# Use 0.0.0.0 for Docker, override with GUNICORN_BIND env var if needed
import os
bind = os.environ.get("GUNICORN_BIND", "127.0.0.1:8000")
workers = 2
worker_class = "sync"
timeout = 30
# Dirty arbiter settings
dirty_apps = [
"examples.dirty_example.dirty_app:MLApp",
"examples.dirty_example.dirty_app:ComputeApp",
"examples.dirty_example.dirty_app:SessionApp",
]
dirty_workers = 2
dirty_timeout = 300
dirty_graceful_timeout = 30
# Logging
loglevel = "info"
accesslog = "-"
errorlog = "-"
# Hooks for demonstration
def on_starting(server):
print("=== Gunicorn starting ===")
def when_ready(server):
print("=== Gunicorn ready ===")
print(f"HTTP workers: {server.num_workers}")
print(f"Dirty workers: {server.cfg.dirty_workers}")
print(f"Dirty apps: {server.cfg.dirty_apps}")
def on_dirty_starting(arbiter):
print("=== Dirty arbiter starting ===")
def dirty_post_fork(arbiter, worker):
print(f"=== Dirty worker {worker.pid} forked ===")
def dirty_worker_init(worker):
print(f"=== Dirty worker {worker.pid} initialized apps ===")
def dirty_worker_exit(arbiter, worker):
print(f"=== Dirty worker {worker.pid} exiting ===")