A Python library for managing background worker processes with persistent state, automatic recovery, and a CLI.
Project description
Crazy Workers
A Python library for managing background worker processes with persistent state, automatic crash recovery, and a built-in CLI.
Features
- Persistent State — SQLite database tracks worker status, PIDs, and parameters across restarts.
- Process Management — Start, stop, and monitor background Python scripts as independent OS processes.
- Automatic Recovery — Detects crashed workers and restarts them on application boot.
- Child Process Control — On stop, terminates unmanaged subprocesses while preserving independently-managed nested workers.
- CLI Interface — Manage workers from the terminal with interactive prompts and auto-discovery (see CLI.md).
- Security — Built-in protection against path traversal in worker type and key names.
- Observability — Per-worker file logging; all service files (DB, lock, logs) live in a
.service/folder inside your workers directory. - Zombie Protection — Distinguishes active processes from zombies using
psutil. - Gunicorn-safe — File-based lock prevents concurrent recovery runs across multiple workers.
Installation
pip install crazy-workers
Or from source:
git clone https://github.com/Vanni-broUser/crazy-workers
cd crazy-workers
pip install .
Quick Start
1. Create a worker script
# workers/my_worker.py
import json, sys, time
params = json.loads(sys.argv[1]) if len(sys.argv) > 1 else {}
duration = params.get('duration', 60)
for _ in range(duration):
time.sleep(1)
2. Manage it from Python
from crazy_workers import WorkerManager
manager = WorkerManager('workers')
# Start
success, result = manager.start_worker(
'my_worker',
worker_key='job_1',
parameters={'duration': 30},
)
print(result['pid']) # OS process ID
print(result['status']) # 'RUNNING'
# List
for w in manager.list_workers():
print(w['worker_key'], w['status'])
# Stop
manager.stop_worker('job_1')
# Recover crashed workers (call on app startup)
restarted = manager.recover_workers()
manager.dispose() # releases DB connection; does NOT kill workers
3. Or from the CLI
crazy-workers list
crazy-workers start my_worker --key job_1 --params '{"duration": 30}'
crazy-workers stop job_1
crazy-workers restore
See CLI.md for full CLI documentation.
API Reference
WorkerManager(workers_dir, create_dir=True)
| Parameter | Type | Default | Description |
|---|---|---|---|
workers_dir |
str |
'workers' |
Directory containing worker .py scripts |
create_dir |
bool |
True |
Create workers_dir and .service/ if they don't exist |
start_worker(worker_type, worker_key=None, parameters=None, env=None)
| Parameter | Type | Default | Description |
|---|---|---|---|
worker_type |
str |
— | Filename (without .py) of the worker script |
worker_key |
str |
worker_type |
Unique identifier; allows multiple instances of the same type |
parameters |
dict |
{} |
JSON-serializable dict passed as sys.argv[1] to the worker |
env |
dict |
None |
Extra environment variables injected into the worker process |
Returns (bool, dict | str) — (True, worker_dict) on success, (False, error_message) on failure.
stop_worker(worker_key)
Gracefully terminates the worker (SIGTERM → SIGKILL after timeout). Returns (bool, str).
list_workers()
Returns a list of worker dicts including RUNNING, STOPPED, CRASHED, and NEVER_STARTED (filesystem-discovered) workers.
recover_workers()
Restarts any worker whose DB status is RUNNING but whose process is dead. Uses a file lock to prevent concurrent recovery. Returns a list of restarted keys.
dispose()
Closes the database connection and clears internal process references. Does not kill background workers — they continue running independently.
Worker Script Contract
A worker receives its parameters as a JSON string in sys.argv[1]:
import json, sys
params = json.loads(sys.argv[1]) if len(sys.argv) > 1 else {}
# ... do work ...
Project Structure
crazy_workers/ # Library package
core/ # WorkerManager, process engine, recovery lock
cli/ # CLI entry point, commands, discovery
database/ # SQLAlchemy schema and SQLite storage
example_app/ # Flask demo application
app.py
workers/ # Example worker scripts
tests/
core/ # Unit tests for core modules
cli/ # Unit tests for CLI modules
database/ # Unit tests for storage layer
integration/ # Full-stack integration tests (real processes)
app/ # Tests for the example Flask app
Flask Integration
from crazy_workers import WorkerManager
def create_app():
app = Flask(__name__)
manager = WorkerManager('workers')
@app.route('/workers/start', methods=['POST'])
def start():
data = request.json
success, result = manager.start_worker(
data['worker_type'],
worker_key=data.get('worker_key'),
parameters=data.get('parameters', {}),
)
return (jsonify(result), 200) if success else (jsonify({'error': result}), 400)
manager.recover_workers() # restart any crashed workers on boot
return app
See example_app/app.py for a complete example.
Gunicorn / Multi-Process Servers
When using a pre-fork server like Gunicorn:
- Recovery is atomic — a file lock (
.service/workers.db.recovery.lock) ensuresrecover_workers()runs once even when multiple workers boot simultaneously. - Workers outlive their parent — if a Gunicorn worker is recycled, background processes keep running. The next recovery cycle re-attaches or restarts them.
Development
Setup
git clone https://github.com/Vanni-broUser/crazy-workers
cd crazy-workers
pip install -e .[dev]
Commands
# Lint and format
ruff check . --fix && ruff format .
# Run tests
pytest
# Run tests with coverage
coverage run -m pytest && coverage report
Standards
See AI.md for the full coding and testing standards used in this project.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crazy_workers-0.1.0.tar.gz.
File metadata
- Download URL: crazy_workers-0.1.0.tar.gz
- Upload date:
- Size: 18.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80260f6f30c6bc552ec518b10b1e30059a1d56e5848ed034d1db1e51520f1520
|
|
| MD5 |
a82b01f23dcdb9b1e81243efc6690555
|
|
| BLAKE2b-256 |
cb50c75a7e47c03279a59c1469f3575e85f29a6e4dc6dfe1fb1adb7148625f08
|
Provenance
The following attestation bundles were made for crazy_workers-0.1.0.tar.gz:
Publisher:
ci.yml on Vanni-broUser/crazy-workers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
crazy_workers-0.1.0.tar.gz -
Subject digest:
80260f6f30c6bc552ec518b10b1e30059a1d56e5848ed034d1db1e51520f1520 - Sigstore transparency entry: 1764049025
- Sigstore integration time:
-
Permalink:
Vanni-broUser/crazy-workers@de6aeb4f6caf2f3e9e860ebeb673753fa8f05e95 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Vanni-broUser
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@de6aeb4f6caf2f3e9e860ebeb673753fa8f05e95 -
Trigger Event:
push
-
Statement type:
File details
Details for the file crazy_workers-0.1.0-py3-none-any.whl.
File metadata
- Download URL: crazy_workers-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bef4f76eee8a3d4c7f9b8eec7340a9bc78a6824aa29eb8ec49b25f3e3dbdd5ca
|
|
| MD5 |
c735d39b19286f3b702c8095c3bab1b4
|
|
| BLAKE2b-256 |
7153f86b72da95a6610349764143ae4dd1f0563e3127c18d3dac81c3fafa9369
|
Provenance
The following attestation bundles were made for crazy_workers-0.1.0-py3-none-any.whl:
Publisher:
ci.yml on Vanni-broUser/crazy-workers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
crazy_workers-0.1.0-py3-none-any.whl -
Subject digest:
bef4f76eee8a3d4c7f9b8eec7340a9bc78a6824aa29eb8ec49b25f3e3dbdd5ca - Sigstore transparency entry: 1764050848
- Sigstore integration time:
-
Permalink:
Vanni-broUser/crazy-workers@de6aeb4f6caf2f3e9e860ebeb673753fa8f05e95 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Vanni-broUser
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@de6aeb4f6caf2f3e9e860ebeb673753fa8f05e95 -
Trigger Event:
push
-
Statement type: