Stream Receive
Receive KubeMQ queue messages via the downstream streaming API using the Python SDK.
Overview
A downstream receiver is the persistent-connection way to pull queue messages: instead of opening and tearing down a request for every batch, you open one gRPC stream and reuse it across many receive cycles. That matters for any consumer that runs continuously — a worker loop, a background processor — where reconnecting per batch would add latency and churn on both the client and the broker.
receive_queue_messages fetches a batch under manual settlement — no auto_ack — so nothing is removed from the queue until you explicitly settle it. Each message is settled on its own: async_ack() permanently removes it, async_nack() returns it for redelivery, and leaving it unsettled returns it once the visibility timeout expires.
Gotchas: a crash between receiving and settling redelivers the whole batch, so processing must be idempotent; forgetting to settle a message just delays its redelivery until the timeout, it doesn't drop it; and mixing ack/nack per message, as shown here, only makes sense for per-item failures — a batch-wide failure is usually better handled by nacking everything and retrying later.
Prerequisites
- KubeMQ server running on
localhost:50000 - Python SDK installed (
pip install kubemq)
Code
"""Example: Stream receive — receive messages with ack/reject/requeue options."""
from __future__ import annotations
import asyncio
from kubemq import AsyncQueuesClient
from kubemq import QueueMessage
async def main() -> None:
async with AsyncQueuesClient(
address="localhost:50000",
client_id="python-queues-stream-stream-receive-client",
) as client:
# Send some test messages
for i in range(3):
await client.send_queue_message(
QueueMessage(
channel="python-queues-stream.stream-receive",
body=f"Message #{i + 1}".encode(),
)
)
print("Sent 3 test messages")
# Receive messages via streaming
response = await client.receive_queue_messages(
channel="python-queues-stream.stream-receive",
max_messages=10,
wait_timeout_seconds=5,
)
for msg in response.messages:
body = msg.body.decode("utf-8")
print(f"Received: {body}")
# Demonstrate different acknowledgment strategies
if "1" in body:
await msg.async_ack()
print(f" -> Acknowledged: {body}")
elif "2" in body:
await msg.async_nack()
print(f" -> Rejected: {body}")
else:
await msg.async_ack()
print(f" -> Acknowledged: {body}")
if __name__ == "__main__":
asyncio.run(main())
How It Works
receive_queue_messagespolls all available messages in a single call (up tomax_messages), returning them as a list withoutauto_ack.- Each message is settled individually:
async_ack()permanently removes it from the queue;async_nack()returns it for redelivery. - The example demonstrates inline decision logic inside the settlement loop, which is the typical pattern for content-based routing to ack or nack.
- Without
auto_ack, the broker holds messages in a visibility-timeout state until settled or until the timeout expires and returns them.
Related
Was this page helpful?