Schema-aware AMQP client for the RocketMQ broker — Pydantic + aio-pika.
Project description
rocketmq-sdk
Schema-aware AMQP client for the RocketMQ broker — Pydantic v2 + aio-pika.
Define message schemas as Pydantic models, publish and consume with full type safety. The broker validates every message against a compiled protobuf schema at wire speed.
from rocketmq import connect
from rocketmq.schema import BaseSchema
class Order(BaseSchema):
id: str
customer_id: str
qty: int
async def main():
mq = await connect(url="amqp://localhost")
orders = await mq.queue("orders", Order)
await orders.send(Order(id="1", customer_id="c1", qty=5))
await orders.consume(lambda msg: print(msg))
await mq.close()
Installation
pip install rocketmq-sdk
Requires Python ≥ 3.11.
Quick Start
1. Connect
from rocketmq import connect
mq = await connect(url="amqp://guest:guest@localhost:5672")
2. Declare a queue with a schema
from rocketmq.schema import BaseSchema
class Notification(BaseSchema):
id: int
content: str
timestamp: float
# Declares the queue + registers the proto3 schema on the broker
notifications = await mq.queue("notifications", Notification)
3. Publish
await notifications.send(Notification(
id=1,
content="Hello from Python",
timestamp=1717520000.0,
))
4. Consume
async def on_notification(msg: Notification) -> None:
print(f"Got: {msg.id} — {msg.content}")
await notifications.consume(on_notification)
5. Close
await mq.close()
API Reference
connect(url, serializer?)
Opens a connection and returns a RocketMQ client.
mq = await connect(url="amqp://localhost")
mq = await connect(url="amqp://localhost", serializer=MySerializer())
RocketMQ
| Method | Description |
|---|---|
await mq.queue(name, Schema) |
Declare queue with schema → returns QueueHandle |
await mq.assert_queue(name, Schema?) |
Declare queue without returning a handle |
await mq.send_to_queue(name, dict) |
Publish a dict directly (untyped) |
await mq.assert_exchange(name, type) |
Declare an exchange |
await mq.bind_queue(queue, exchange, routing_key) |
Bind queue to exchange |
await mq.publish(exchange, routing_key, dict) |
Publish to exchange |
await mq.consume(queue, Schema, handler) |
Subscribe with typed handler |
await mq.prefetch(count) |
Set channel prefetch |
await mq.close() |
Close channel + connection |
QueueHandle[T]
Typed wrapper returned by mq.queue(). All operations are bound to one queue + schema.
orders = await mq.queue("orders", Order)
# Typed publish — payload must be an Order instance
await orders.send(Order(id="1", customer_id="c1", qty=5))
# Typed consume — handler receives Order, not raw bytes
await orders.consume(lambda msg: print(msg.id))
Schemas
Defining a schema
Every message schema is a frozen Pydantic model:
from rocketmq.schema import BaseSchema
class OrderEvent(BaseSchema):
order_id: str
action: str
amount: float
The class name (OrderEvent) becomes the protobuf message name.
Fields are automatically mapped to proto3 types.
Type mapping
| Python | Proto3 | Notes |
|---|---|---|
str |
string |
|
int |
int32 |
Default for integers |
float |
double |
|
bool |
bool |
|
bytes |
bytes |
|
datetime |
google.protobuf.Timestamp |
Adds import |
list[str] |
repeated string |
Any inner type |
int | None |
optional int32 |
Optional fields |
Overriding proto types
Use Proto() annotation for cross-language compatibility:
from typing import Annotated
from rocketmq.schema import BaseSchema, Proto
class Metric(BaseSchema):
sensor_id: str
value: Annotated[float, Proto("float")] # float instead of double
count: Annotated[int, Proto("int64")] # int64 instead of int32
big_id: Annotated[int, Proto("uint64")] # unsigned
Available proto types: double, float, int32, int64, uint32, uint64,
sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, string, bytes.
Schema validation
The broker validates every published message against the queue's compiled schema. If a field is missing or has the wrong type, the broker rejects the message:
from rocketmq.errors import SchemaValidationError
try:
await mq.send_to_queue("orders", {"wrong_field": 123})
except SchemaValidationError as err:
print(err.code) # "SchemaTypeMismatch"
print(err.queue) # "orders"
print(err.fields) # [FieldErrorDetail(name="id", expected="str", got="missing")]
Consumer schema verification
When consuming, the SDK sends the consumer's schema to the broker. The broker verifies compatibility before delivering any message:
# Fails at subscribe time if NewOrder is incompatible with the queue's schema
await mq.consume("orders", NewOrder, handler)
# Override the queue's schema with the consumer's schema
await mq.consume("orders", NewOrder, handler, schema_override=True)
# Remove the queue's schema entirely
await mq.consume("orders", NewOrder, handler, schema_delete=True)
Exchange Routing
For topic/direct/fanout/headers routing:
# Declare exchange + queues
await mq.assert_exchange("events", "direct")
await mq.assert_queue("events.created", OrderEvent)
await mq.assert_queue("events.cancelled", OrderEvent)
await mq.bind_queue("events.created", "events", "created")
await mq.bind_queue("events.cancelled", "events", "cancelled")
# Publish to specific routing keys
await mq.publish("events", "created", {
"order_id": "ord-001",
"action": "created",
"amount": 99.90,
})
# Consume from specific queues
await mq.consume("events.created", OrderEvent, lambda msg: print(f"NEW: {msg}"))
await mq.consume("events.cancelled", OrderEvent, lambda msg: print(f"CANCEL: {msg}"))
Custom Serializer
Swap JSON for any encoding (msgpack, protobuf, avro, etc.):
import msgpack
from typing import cast
class MsgpackSerializer:
@property
def content_type(self) -> str:
return "application/x-msgpack"
def serialize(self, value: object) -> bytes:
return cast("bytes", msgpack.packb(value, use_bin_type=True))
def deserialize(self, data: bytes) -> object:
return msgpack.unpackb(data, raw=False)
mq = await connect(url="amqp://localhost", serializer=MsgpackSerializer())
No base class needed — any object with content_type, serialize(), and deserialize() works.
Error Handling
All errors extend RocketMQError:
RocketMQError
├── ConnectionError_ # Connection failures
├── QueueError # Queue declaration failures
├── PublishError # Publish failures (.queue, .payload)
├── ConsumeError # Subscribe failures
├── SerializationError # Encode/decode failures (.payload)
├── SchemaError # Schema compilation issues
│ └── SchemaValidationError # Type mismatch (.code, .queue, .fields)
└── TimeoutError_ # Operation timeouts
from rocketmq.errors import PublishError, SchemaValidationError
try:
await mq.send_to_queue("orders", payload)
except SchemaValidationError as err:
# Structured: err.code, err.queue, err.fields
for field in err.fields:
print(f" {field.name}: expected {field.expected}, got {field.got}")
except PublishError as err:
# Generic: err.queue, err.payload
print(f"Failed on {err.queue}")
Development
uv sync # install deps
make fmt # format (ruff)
make lint # lint (ruff)
make typecheck # type-check (pyright)
make test # run tests (pytest)
make check # lint + typecheck + test
make all # format + fix + typecheck + test
Architecture
src/rocketmq/
├── __init__.py # Public re-exports
├── py.typed # PEP 561 marker
├── amqp.py # Thin aio-pika wrapper
├── client.py # RocketMQ + connect() + QueueHandle
├── schema.py # BaseSchema + Proto annotation
├── proto.py # Pydantic model → proto3 generator
├── serializer.py # Serializer Protocol + JsonSerializer
├── errors.py # Error hierarchy
├── error_codes.py # BrokerErrorCode enum
└── error_parser.py # Broker JSON error parsing
License
MIT
Project details
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 rocketmq_sdk-0.1.1.tar.gz.
File metadata
- Download URL: rocketmq_sdk-0.1.1.tar.gz
- Upload date:
- Size: 74.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 |
e442eb1b7218d214db75def9a4540313e12733a60b7398587b6cce94b3d588ca
|
|
| MD5 |
4800ee031fe31fe075d19c982f44fac8
|
|
| BLAKE2b-256 |
c5ed581b8fcff2450c168dbc52582832088c22032eff2a15ebe1cd1d702c206a
|
Provenance
The following attestation bundles were made for rocketmq_sdk-0.1.1.tar.gz:
Publisher:
publish.yml on rocketmq-broker/rocketmq.py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rocketmq_sdk-0.1.1.tar.gz -
Subject digest:
e442eb1b7218d214db75def9a4540313e12733a60b7398587b6cce94b3d588ca - Sigstore transparency entry: 1738766861
- Sigstore integration time:
-
Permalink:
rocketmq-broker/rocketmq.py@c1b0dfff8e3fca21c1fd3ab6d339ef905be706d6 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/rocketmq-broker
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c1b0dfff8e3fca21c1fd3ab6d339ef905be706d6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file rocketmq_sdk-0.1.1-py3-none-any.whl.
File metadata
- Download URL: rocketmq_sdk-0.1.1-py3-none-any.whl
- Upload date:
- Size: 20.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 |
518c7096b6d632ab1b3deb9258b5b99ab31ee96e7dcea47ba98275258737c077
|
|
| MD5 |
4efb7220d5fe7691dd609102da42b4be
|
|
| BLAKE2b-256 |
9b5f6b8b129dddb42f8d91d3ec2cc375c547c97b01536611827bfcdc37106924
|
Provenance
The following attestation bundles were made for rocketmq_sdk-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on rocketmq-broker/rocketmq.py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rocketmq_sdk-0.1.1-py3-none-any.whl -
Subject digest:
518c7096b6d632ab1b3deb9258b5b99ab31ee96e7dcea47ba98275258737c077 - Sigstore transparency entry: 1738766972
- Sigstore integration time:
-
Permalink:
rocketmq-broker/rocketmq.py@c1b0dfff8e3fca21c1fd3ab6d339ef905be706d6 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/rocketmq-broker
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c1b0dfff8e3fca21c1fd3ab6d339ef905be706d6 -
Trigger Event:
push
-
Statement type: