Skip to content

Commit 217013b

Browse files
authored
Merge pull request #61 from gmr/feature/cleanup
Docs: rewrite for 4.0, add migration guide, update CLAUDE.md
2 parents f581ab9 + db3373c commit 217013b

14 files changed

Lines changed: 1026 additions & 448 deletions

CLAUDE.md

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,68 @@
1-
# Rejected
1+
# CLAUDE.md
22

3-
Rejected is a Python RabbitMQ Consumer Framework and Controller Daemon.
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project
6+
7+
Rejected is a Python RabbitMQ Consumer Framework and Controller Daemon. It manages consumer processes that connect to RabbitMQ, receive messages, and process them with user-defined consumer classes.
48

59
## Development
610

711
```bash
8-
UV_CONFIG_FILE=/dev/null uv sync --all-groups # Install all dependencies
9-
UV_CONFIG_FILE=/dev/null uv run coverage run # Run tests with coverage
10-
UV_CONFIG_FILE=/dev/null uv run coverage report # View coverage report
11-
UV_CONFIG_FILE=/dev/null uv run pre-commit run -a # Run linting
12+
UV_CONFIG_FILE=/dev/null uv sync --all-groups # Install all dependencies
13+
UV_CONFIG_FILE=/dev/null uv run coverage run # Run all tests with coverage
14+
UV_CONFIG_FILE=/dev/null uv run coverage report # View coverage report
15+
UV_CONFIG_FILE=/dev/null uv run pre-commit run -a # Run linting (ruff format + ruff check)
1216
```
1317

14-
## Documentation
18+
To run a single test:
19+
```bash
20+
UV_CONFIG_FILE=/dev/null .venv/bin/python -m unittest tests.test_consumer.ConsumerExecuteTests.test_execute_calls_process
21+
```
1522

23+
Documentation:
1624
```bash
17-
UV_CONFIG_FILE=/dev/null uv run mkdocs serve # Serve docs locally at http://127.0.0.1:8000
18-
UV_CONFIG_FILE=/dev/null uv run mkdocs build # Build docs to site/
25+
UV_CONFIG_FILE=/dev/null uv run mkdocs serve # Serve docs locally at http://127.0.0.1:8000
26+
UV_CONFIG_FILE=/dev/null uv run mkdocs build # Build docs to site/
1927
```
2028

29+
## Important Notes
30+
31+
- Use `UV_CONFIG_FILE=/dev/null` for all uv commands — this repo is on github.com, not the internal AWeber PyPI
32+
- Tests use unittest discovery with `-s tests -t .` to support relative imports in the test package
33+
- `rejected/consumer.py` has intentional suppression of B904/BLE001/C901 for error handling complexity
34+
- `rejected/process.py` has intentional C901 suppression
35+
2136
## Code Style
2237

2338
- Ruff for linting and formatting (configured in pyproject.toml)
2439
- Single quotes for strings
2540
- 79 character line length
26-
- `rejected/consumer.py` has intentional suppression of B904/C901 for Tornado gen.Return pattern
2741

28-
## Notes
42+
## Architecture
2943

30-
- Use `UV_CONFIG_FILE=/dev/null` for all uv commands — this repo is on github.com, not the internal AWeber PyPI
31-
- Tests use unittest discovery with `-s tests -t .` to support relative imports in the test package
32-
- `pkg_resources` has been replaced with `importlib.metadata` throughout
44+
### Process Model
45+
46+
`Controller` (CLI entry point) → `MasterControlProgram` (MCP) → N × `Process` (multiprocessing.Process)
47+
48+
Each `Process` runs an asyncio event loop with one or more pika `AsyncioConnection`s. The MCP polls child processes via `SIGPROF`/`SIGALRM` signals, collects stats via a multiprocessing Queue, and manages process lifecycle (spawn, kill unresponsive, restart on errors).
49+
50+
### Message Flow
51+
52+
1. `Connection` receives a message from RabbitMQ via pika callbacks
53+
2. `Process.on_message` builds a `ProcessingContext` (Pydantic model) and schedules `invoke_consumer`
54+
3. `invoke_consumer` decodes the body via `Codec`, then calls `consumer.execute(ctx)`
55+
4. `_Consumer.execute` runs pre-validation (message type, retry limits), then delegates to `_run_consumer`
56+
5. `Consumer._run_consumer` acquires a lock and calls `prepare()``process()``finish()`; `TransactionConsumer._run_consumer` calls them without a lock, passing `ctx` as an argument
57+
6. `Process.on_processed` handles the result: ack, nack, requeue, or republish based on the `Result` enum
58+
59+
### Key Module Responsibilities
60+
61+
- **consumer.py**: `_Consumer` base, `Consumer` (locked, self.body-style), `TransactionConsumer` (concurrent, ctx-style)
62+
- **codecs.py**: `Codec` class handles encode/decode dispatch by content_type/content_encoding, plus async Avro schema loading
63+
- **connection.py**: Wraps pika `AsyncioConnection`, manages channel lifecycle, QoS, consumer tags
64+
- **process.py**: `Process(multiprocessing.Process)` — the per-consumer child process with asyncio event loop
65+
- **mcp.py**: `MasterControlProgram` — parent process that spawns/monitors/polls child processes
66+
- **models.py**: All Pydantic models — `Config`, `ConsumerConfig`, `ConnectionConfig`, `Message`, `ProcessingContext`, `Result`
67+
- **state.py**: `State` base class with state machine (INITIALIZING → CONNECTING → IDLE → ACTIVE → SHUTTING_DOWN → STOPPED)
68+
- **testing.py**: `AsyncTestCase(IsolatedAsyncioTestCase)` for consumer unit tests with mocked RabbitMQ

README.md

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,19 @@ each run in an isolated process. It has the ability to collect statistical
1010
data from the consumer processes and report on it.
1111

1212
[![Version](https://img.shields.io/pypi/v/rejected.svg?)](https://pypi.python.org/pypi/rejected)
13+
[![Python](https://img.shields.io/pypi/pyversions/rejected.svg)](https://pypi.python.org/pypi/rejected)
1314
[![License](https://img.shields.io/pypi/l/rejected.svg?)](https://github.com/gmr/rejected/blob/main/LICENSE)
1415

1516
## Features
1617

18+
- Async consumers built on `asyncio`
1719
- Automatic exception handling including connection management and consumer restarting
18-
- Smart consumer classes that can automatically decode and deserialize message bodies based upon message headers
19-
- Metrics logging and submission to statsd and InfluxDB
20+
- Smart consumer classes that automatically decode and deserialize message bodies based on message headers
21+
- Concurrent message processing with `TransactionConsumer`
22+
- Metrics via statsd and/or Prometheus
2023
- Built-in profiling of consumer code
21-
- Ability to write asynchronous code in consumers allowing for parallel communication with external resources
24+
- Avro schema support with file and HTTP schema registries
25+
- YAML and TOML configuration file support
2226

2327
## Installation
2428

@@ -29,9 +33,11 @@ pip install rejected
2933
For optional features:
3034

3135
```bash
32-
pip install rejected[avro] # Avro support
33-
pip install rejected[html] # HTML message body support
34-
pip install rejected[msgpack] # MessagePack support
36+
pip install rejected[avro] # Avro datum serialization
37+
pip install rejected[html] # HTML message body support
38+
pip install rejected[msgpack] # MessagePack support
39+
pip install rejected[prometheus] # Prometheus metrics exporter
40+
pip install rejected[sentry] # Sentry error reporting
3541
```
3642

3743
## Documentation
@@ -52,3 +58,18 @@ class Test(consumer.Consumer):
5258
async def process(self) -> None:
5359
LOGGER.debug('In Test.process: %s', self.body)
5460
```
61+
62+
For concurrent message processing, use `TransactionConsumer`:
63+
64+
```python
65+
from rejected import consumer, models
66+
import logging
67+
68+
LOGGER = logging.getLogger(__name__)
69+
70+
71+
class Test(consumer.TransactionConsumer):
72+
73+
async def process(self, ctx: models.ProcessingContext) -> None:
74+
LOGGER.debug('Processing: %s', ctx.message.body)
75+
```

docs/api.md

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,104 @@
44

55
The primary base classes for building message consumers.
66

7+
### Consumer
8+
79
::: rejected.consumer.Consumer
10+
options:
11+
members:
12+
- process
13+
- prepare
14+
- finish
15+
- on_finish
16+
- initialize
17+
- shutdown
18+
- on_blocked
19+
- on_unblocked
20+
- on_confirmation
21+
- publish_message
22+
- set_sentry_context
23+
- unset_sentry_context
24+
- send_exception_to_sentry
25+
- require_setting
26+
- stats_add_duration
27+
- stats_incr
28+
- stats_set_tag
29+
- stats_set_value
30+
- stats_track_duration
31+
- body
32+
- app_id
33+
- content_encoding
34+
- content_type
35+
- correlation_id
36+
- exchange
37+
- expiration
38+
- headers
39+
- message_id
40+
- message_type
41+
- name
42+
- priority
43+
- properties
44+
- redelivered
45+
- reply_to
46+
- returned
47+
- routing_key
48+
- settings
49+
- timestamp
50+
- user_id
51+
52+
### TransactionConsumer
53+
54+
::: rejected.consumer.TransactionConsumer
55+
options:
56+
members:
57+
- process
58+
- prepare
59+
- finish
60+
- initialize
61+
- shutdown
862

963
## Exceptions
1064

11-
::: rejected.consumer.ConsumerException
65+
::: rejected.exceptions.ConsumerException
66+
67+
::: rejected.exceptions.MessageException
68+
69+
::: rejected.exceptions.ProcessingException
70+
71+
::: rejected.exceptions.RejectedException
72+
73+
## Models
1274

13-
::: rejected.consumer.MessageException
75+
### Message
1476

15-
::: rejected.consumer.ProcessingException
77+
::: rejected.models.Message
1678

17-
::: rejected.consumer.RejectedException
79+
### ProcessingContext
80+
81+
::: rejected.models.ProcessingContext
82+
83+
### Result
84+
85+
::: rejected.models.Result
1886

1987
## Testing
2088

2189
::: rejected.testing.AsyncTestCase
90+
options:
91+
members:
92+
- get_consumer
93+
- get_settings
94+
- create_context
95+
- process_message
96+
- published_messages
97+
- measurement
98+
99+
::: rejected.testing.PublishedMessage
100+
101+
## Measurement
102+
103+
::: rejected.measurement.Measurement
22104

23-
## Data
105+
## Mixins
24106

25-
::: rejected.data.Measurement
107+
::: rejected.mixins.GarbageCollectorMixin

docs/api_consumer.rst

Lines changed: 0 additions & 7 deletions
This file was deleted.

docs/api_data.rst

Lines changed: 0 additions & 5 deletions
This file was deleted.

docs/api_testing.rst

Lines changed: 0 additions & 5 deletions
This file was deleted.

docs/cli.rst

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)