Skip to main content

Python bindings for tokio-memq

Project description

tokio-memq-python

PyPI version Build Status License: MIT Python Version

tokio-memq-python is a high-performance, asynchronous in-memory message queue library for Python, powered by the robust Rust tokio-memq crate.

It bridges the gap between Python's ease of use and Rust's performance, providing a seamless asyncio interface for building high-throughput, low-latency messaging applications. Whether you are building a local event bus, a job queue, or a high-speed data pipeline, tokio-memq-python offers the speed and reliability you need.

Features

  • 🚀 High Performance: Built on Rust's Tokio runtime, offering exceptional throughput and low latency.
  • ⚡ Async/Await Native: Fully integrated with Python's asyncio for non-blocking I/O. Supports async for loops.
  • � Consumer Groups: Built-in support for competing consumers pattern with automatic load balancing.
  • � Partition Support: Scale horizontally with built-in partitioned topics and flexible routing strategies (RoundRobin, Hash, Random, Fixed).
  • 🛠 Type Safety: Leverages Rust's strong type system to ensure stability and correctness.
  • 🔧 Cross-Platform: Pre-compiled wheels available for Linux, Windows, and macOS (Intel & Apple Silicon).
  • ⚙️ Configurable: Fine-tune queue depth, message TTL (Time-To-Live), and eviction policies (LRU).

� Use Cases

  • High-Performance Event Bus: Decouple components in your Python application with minimal latency overhead.
  • Async Job Processing: Efficiently distribute tasks to worker coroutines or threads using consumer groups.
  • Data Streaming Pipelines: Handle high-velocity data ingestion and processing with backpressure support.
  • Local Microservices Communication: Fast inter-process-like communication within a single application instance.
  • Testing & Simulation: Simulate complex distributed messaging scenarios (like Kafka/RabbitMQ) locally without infrastructure overhead.

�📊 Benchmarks

Environment:

  • OS: macOS
  • Device: Apple M4 (24GB RAM)
  • Python: 3.12

Results (Run with python3 examples/benchmark.py --count 10000):

Scenario Metric Result Resource Usage (Avg CPU / Peak Mem)
Latency (1 Pub → 1 Sub) Avg Latency 120.17 µs N/A
P99 Latency 174.55 µs
Throughput (1 Pub → 1 Sub) Publish Rate 12,883 msg/s 148% / 37 MB
Consume Rate 12,882 msg/s
Fan-Out (1 Pub → 5 Sub) Publish Rate 6,647 msg/s 216% / 40 MB
Total Consume Rate 28,306 msg/s
Fan-In (5 Pub → 1 Sub) Publish Rate 32,974 msg/s 143% / 44 MB
Consume Rate 13,662 msg/s

Note: Benchmarks include Python object serialization overhead. Raw Rust performance is significantly higher. Resource usage reflects the Python process overhead.

Installation

pip install tokio-memq-python

Requires Python 3.8 or later.

Examples

1. Basic Publish-Subscribe

A simple example demonstrating how to create a queue, publish messages, and consume them asynchronously.

import asyncio
from tokio_memq import MessageQueue

async def main():
    # Initialize the Message Queue
    mq = MessageQueue()
    
    # Create a publisher for "notifications"
    publisher = mq.publisher("notifications")
    
    # Create a subscriber for the same topic
    # This automatically creates the topic if it doesn't exist
    subscriber = await mq.subscriber("notifications")
    
    # Publish messages (any JSON-serializable data)
    await publisher.send({"type": "email", "to": "user@example.com"})
    await publisher.send({"type": "sms", "to": "+1234567890"})
    
    # Process messages using async iterator
    async for msg in subscriber:
        print(f"Processed notification: {msg}")
        # For this example, break after 2 messages
        if msg["type"] == "sms":
            break

if __name__ == "__main__":
    asyncio.run(main())

2. Consumer Groups (Load Balancing)

Multiple consumers can join a group to share the workload. Messages are distributed among active consumers.

import asyncio
from tokio_memq import MessageQueue

async def worker(mq, topic, group_id, name):
    # Join a consumer group with "Earliest" mode to get existing messages
    sub = await mq.subscriber_group(topic, group_id, mode="Earliest")
    print(f"[{name}] Joined group '{group_id}' (ID: {sub.consumer_id})")
    
    async for msg in sub:
        print(f"[{name}] Processing: {msg}")

async def main():
    mq = MessageQueue()
    topic = "jobs"
    group = "workers"
    
    # Start two workers
    w1 = asyncio.create_task(worker(mq, topic, group, "Worker-1"))
    w2 = asyncio.create_task(worker(mq, topic, group, "Worker-2"))
    
    # Publish tasks
    pub = mq.publisher(topic)
    for i in range(10):
        await pub.send({"task_id": i})
        
    # Keep running...

if __name__ == "__main__":
    asyncio.run(main())

3. Partitioned Topics with Hash Routing

This example shows how to use partitioned topics to distribute load while ensuring message ordering for specific keys (e.g., user IDs).

import asyncio
from tokio_memq import MessageQueue

async def main():
    mq = MessageQueue()
    topic = "user_activity"
    
    # Create a topic with 4 partitions for parallel processing
    await mq.create_partitioned_topic(topic, partition_count=4)
    
    # Configure "Hash" routing: messages with the same key go to the same partition
    await mq.set_partition_routing(topic, "Hash", key="message")
    
    pub = mq.publisher(topic)
    
    # Simulate user events
    # Events for 'user_123' will always land in the same partition
    await pub.send({"event": "login"}, key="user_123")
    await pub.send({"event": "view_item"}, key="user_123")
    
    # Events for 'user_456' will land in a different partition (likely)
    await pub.send({"event": "logout"}, key="user_456")
    
    # Consume from a specific partition (e.g., Partition 0)
    # Use mode="Earliest" to ensure we get messages published before we subscribed
    sub_p0 = await mq.subscribe_partition(topic, 0, mode="Earliest")
    
    print("Listening on Partition 0...")
    try:
        msg = await asyncio.wait_for(sub_p0.recv(), timeout=1.0)
        print(f"Partition 0 received: {msg}")
    except asyncio.TimeoutError:
        print("No messages on Partition 0 for this run.")

if __name__ == "__main__":
    asyncio.run(main())

4. Advanced Configuration (TTL & Queue Limits)

Control memory usage and message lifecycle using TopicOptions.

import asyncio
from tokio_memq import MessageQueue, TopicOptions

async def main():
    mq = MessageQueue()
    
    # Configure topic options
    opts = TopicOptions()
    opts.max_messages = 100        # Limit queue to 100 messages
    opts.message_ttl_ms = 5000     # Messages expire after 5 seconds
    opts.lru_enabled = True        # Drop oldest messages when full
    
    # Create subscriber with custom options
    sub = await mq.subscriber_with_options("fast_logs", opts)
    pub = mq.publisher("fast_logs")
    
    # Publish a message
    await pub.send("This message will self-destruct in 5s")
    
    msg = await sub.recv()
    print(f"Got: {msg}")

if __name__ == "__main__":
    asyncio.run(main())

More Examples

Check the examples/ directory for ready-to-run scripts:

API Reference

MessageQueue

The central manager for topics, publishers, and subscribers.

  • publisher(topic: str) -> Publisher: Get a publisher for a topic.
  • subscriber(topic: str) -> Subscriber: Subscribe to a topic (auto-creates it).
  • subscriber_with_options(topic: str, options: TopicOptions) -> Subscriber: Subscribe with specific configuration.
  • subscriber_group(topic: str, consumer_id: str, mode: str = "LastOffset", offset: int = None) -> Subscriber: Join a consumer group.
    • consumer_id: Unique ID for the consumer group member.
    • mode: "Earliest", "Latest", "LastOffset", or "Offset".
  • create_partitioned_topic(topic: str, partition_count: int, options: TopicOptions = None): Create a topic with n partitions.
  • set_partition_routing(topic: str, strategy: str, key: str = None, fixed_id: int = None): Set routing logic.
    • strategy: "RoundRobin", "Random", "Hash", "Fixed".
    • key: Required for "Hash" routing (e.g., "message").
    • fixed_id: Required for "Fixed" routing (target partition ID).
  • subscribe_partition(topic: str, partition_id: int, consumer_id: str = None, mode: str = "LastOffset", offset: int = None) -> Subscriber: Listen to a specific partition.
  • list_partitioned_topics() -> List[str]: List active partitioned topics.
  • delete_partitioned_topic(topic: str): Delete a topic.

Publisher

  • send(data: Any, key: str = None): Send a message (alias for publish).
    • data: JSON-serializable payload (dict, list, str, int, etc.).
    • key: Routing key (used only if topic is partitioned with Hash routing).
  • publish(data: Any, key: str = None): Send a message.
  • topic() -> str: Get the topic name.

Subscriber

  • recv() -> Any: Await the next message. Raises exception if connection is lost.
  • try_recv() -> Any | None: Non-blocking receive. Returns None if no message available.
  • current_offset() -> int: Get current offset.
  • reset_offset(): Reset offset to 0.
  • consumer_id -> str | None: (Property) Get the consumer ID if applicable.
  • topic -> str: (Property) Get the topic name.
  • Async Iterator: Supports async for msg in subscriber: syntax.

TopicOptions

  • max_messages (int): Max messages per topic/partition.
  • message_ttl_ms (int): Message lifetime in milliseconds.
  • lru_enabled (bool): If True, drops oldest message when full; otherwise rejects new messages.
  • partitions (int): (Read-only) Number of partitions if applicable.

License

This project is licensed under the MIT License.

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

tokio_memq_python-0.1.3.tar.gz (26.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

tokio_memq_python-0.1.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded PyPymanylinux: glibc 2.17+ x86-64

tokio_memq_python-0.1.3-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl (1.5 MB view details)

Uploaded PyPymanylinux: glibc 2.17+ i686

tokio_memq_python-0.1.3-cp38-abi3-win_amd64.whl (1.1 MB view details)

Uploaded CPython 3.8+Windows x86-64

tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ x86-64

tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.4 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ s390x

tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.5 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ppc64le

tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl (1.5 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ i686

tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (1.3 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARMv7l

tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.4 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

tokio_memq_python-0.1.3-cp38-abi3-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

tokio_memq_python-0.1.3-cp38-abi3-macosx_10_12_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

Details for the file tokio_memq_python-0.1.3.tar.gz.

File metadata

  • Download URL: tokio_memq_python-0.1.3.tar.gz
  • Upload date:
  • Size: 26.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.10.2

File hashes

Hashes for tokio_memq_python-0.1.3.tar.gz
Algorithm Hash digest
SHA256 6085303b3797226a7ea428e26c1cf31af42f06c4520139b6edbd131c2ec942d7
MD5 2540168d411ab2a9058c4a4fcbc1190d
BLAKE2b-256 a9b7ab924cdf4f19627e842bc7f180249b333d3b16c3dda775ab0649b4db1153

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e67e885bbdc316ab49b6e867009746acfe1f733dd19619510a850aed831f628d
MD5 c32b6b78d99a29b97f2f174874375bbf
BLAKE2b-256 8c2aa400644593dc95048ba1f7e9151746a5d92d0efd3416378844098bc460ed

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 dbd5f6cfec576b12b163d29f1e2aef7d8b94251532e7ac5d3f33272347b83b1e
MD5 695333c55ebc4a84f827891d61ea6240
BLAKE2b-256 f97331d990f7eb04e5272e282bc01ad1d43a5059bfe840eee75387099c6f2783

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 6095021d561479270e9c413dfc13a33f3ffe24ba548db3f3a7eb17aaccd799da
MD5 8c69c7facd37b5743d82a167734937c9
BLAKE2b-256 f428224a39c35eaddede23d080727d9735489aada3d5a72e4c9ec5e0229004a1

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b188280f763a534b0f3c748068649aa3e963e071e0dcb4e9af769260f8d43ba0
MD5 0a8b1bc2a58dab67bce220bfc0c4c2b7
BLAKE2b-256 40c38b5ac6eff71b0cac0e9fa3240fa19ea7e01106ad55232e10ec9926fe5537

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 29302770ab5acfe73274675c68946718c4726d0164a6a315e0a646e20a42ccac
MD5 a6c24eae5a79603ae8833a2ae9229d5d
BLAKE2b-256 84fb867614b0cb76c5cdd907d3264691ea9a2a92552f68e6f01850cfe12d483c

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 9302fda4f65bd567f8542a54653ea923334dd4d85fb3ba7d47f96ebb143b9341
MD5 64b34f529ff2423d311f2f9336d118e0
BLAKE2b-256 3ce0b3f25fc9090df4ccb7af02c6155a6c84194c3c146ced4b116db9465964cc

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 1babfa61d96d2e690de138748157501f3f43d086b972abb3e336eb06753b6515
MD5 362ba21b0b9fc78aa5158345a6dc9653
BLAKE2b-256 06b5489e8e6532f9024aaa3df1aa607cf0e7e2d1646a72c1eff807bb15cc8c53

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 d2ae8564dae95f96785142dc036866d847f26d70bb8913faa36b5ebda18ad027
MD5 7cb4432dd71c5d6eefada100cc651971
BLAKE2b-256 9c61754672cc8393cfd241dc245d7ffd68eed177b35c43afa507292d39706178

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f2f2d1d1a375a25f6fe8bd8848c03d0e7bb34e43202cac3a5f6aba7c15d49c2c
MD5 e6eef99292e64c11a88b71fd9333f9da
BLAKE2b-256 f79d2779f8bc0a8c5b0e282510632cc14229732c04e311ff545a5fe0f0eab00e

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a4ef7606c0bc0c54cd55b6a11bc0af2c9dc1387f3619c0e44e19434a0b7664a3
MD5 70c8978a30b5424e5cf937db5dcedf1c
BLAKE2b-256 df35c81b6875d93dc24a71ab869bdb089c65cc349f9b2c901f254e6f54cebd4b

See more details on using hashes here.

File details

Details for the file tokio_memq_python-0.1.3-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for tokio_memq_python-0.1.3-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 9c8167339b77a580f6038995ee1e90cef599a2e2cab9027bf0502a3d1ca39c87
MD5 63785825b40edfed8af864f3a8a37c86
BLAKE2b-256 b59eec94fd19402909869ceb4c1e177a11e2f18fabd49e0603d91a32f1f6ddd0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page