Broker Execution Transports¶
In addition to local workers and serverless Google Cloud transports, litestar-queues provides four message broker execution transports:
- Google Cloud Pub/Sub (
PubSubExecutionConfig, extralitestar-queues[pubsub]) - Amazon SQS (
SqsExecutionConfig, extralitestar-queues[sqs]) - RabbitMQ 4.3+ (
RabbitMQExecutionConfig, extralitestar-queues[rabbitmq]) - Apache Kafka (
KafkaExecutionConfig, extralitestar-queues[kafka])
Runnable Configuration Example¶
"""Configuring Pub/Sub, Amazon SQS, RabbitMQ, and Apache Kafka execution transports."""
from litestar_queues import QueueConfig, WorkerConfig
from litestar_queues.backends.redis import RedisBackendConfig
from litestar_queues.execution.kafka import KafkaExecutionConfig
from litestar_queues.execution.pubsub import PubSubExecutionConfig
from litestar_queues.execution.rabbitmq import RabbitMQExecutionConfig
from litestar_queues.execution.sqs import SqsExecutionConfig
def build_broker_configs() -> dict[str, QueueConfig]:
"""Construct QueueConfig instances for all four message broker execution transports."""
storage = RedisBackendConfig(url="redis://redis.internal:6379/0")
return {
"pubsub": QueueConfig(
queue_backend=storage,
execution_backend=PubSubExecutionConfig(
project_id="my-gcp-project",
topic_id="litestar-queue-tasks",
subscription_id="litestar-queue-tasks-sub",
ack_deadline=60,
ack_extension_interval=30,
),
worker=WorkerConfig(placement="external"),
),
"sqs": QueueConfig(
queue_backend=storage,
execution_backend=SqsExecutionConfig(
queue_url="https://sqs.us-east-1.amazonaws.com/123456789012/litestar-queues",
region_name="us-east-1",
wait_time_seconds=20,
visibility_timeout=60,
visibility_extension_interval=30,
),
worker=WorkerConfig(placement="external"),
),
"rabbitmq": QueueConfig(
queue_backend=storage,
execution_backend=RabbitMQExecutionConfig(
amqp_url="amqps://app:secret@rabbitmq.internal:5671/prod",
queue_name="litestar-queues.tasks",
declare_queue=True,
delayed_retry_type="returned",
),
worker=WorkerConfig(placement="external"),
),
"kafka": QueueConfig(
queue_backend=storage,
execution_backend=KafkaExecutionConfig(
bootstrap_servers="kafka-1.internal:9092,kafka-2.internal:9092",
topic="litestar-queues-tasks",
consumer_group="litestar-queues-consumers",
),
worker=WorkerConfig(placement="external"),
),
}
async def main() -> None:
"""Verify broker execution configurations validate cleanly."""
configs = build_broker_configs()
assert set(configs) == {"pubsub", "sqs", "rabbitmq", "kafka"}
pubsub_backend = configs["pubsub"].execution_backend
assert isinstance(pubsub_backend, PubSubExecutionConfig)
assert pubsub_backend.topic_path == "projects/my-gcp-project/topics/litestar-queue-tasks"
Shared Broker Architecture: Dispatcher + Consumer Fleet¶
Unlike Cloud Tasks (schedules_on_enqueue=True), general-purpose message brokers do not natively store 30-day delayed schedules, uniqueness reservations, or fenced retry state. litestar-queues therefore pairs your authoritative storage backend with a two-role broker topology:
- Worker Dispatcher (
litestar queues run): Claims duependingandscheduledrecords from the storage backend, reserves a monotonic attempt generation (litestar_queues_attempt), and publishes an ID-only message ({"version": 1, "task_id": "<uuid>"}) to the broker topic or queue. - Broker Consumer Fleet (
litestar queues run-consumer --backend <name>): Pulls ID-only messages from the broker subscription, verifies the attempt generation fence against the storage backend, executes the task body while sending periodic worker heartbeats to the storage backend, and acknowledges the broker message once the attempt reaches a durable storage transition.
ID-Only Wire Envelope & Generation Fencing¶
Every broker message payload contains only {"version": 1, "task_id": "<uuid>"} plus transport metadata headers (litestar_queues_attempt, litestar_queues_queue, litestar_queues_task_name). Task arguments, keyword arguments, results, and metadata never travel across the broker wire.
Because message brokers provide at-least-once delivery, duplicate or delayed broker redeliveries are fenced against the storage record's retry_count and execution_ref:
- If a duplicate broker message arrives while the attempt is already terminal or has rotated to a newer
retry_count, the consumer acknowledges and drops the stale message without re-executing the task. - If a consumer crashes mid-attempt,
QueueMaintenanceService(or the dispatcher's reconciliation pass) rotates the stale attempt afterdispatch_stale_afterseconds and republishes a fresh generation. - Broker-level redelivery timers (such as SQS message visibility, Pub/Sub ack deadlines, or RabbitMQ consumer timeouts) govern only transport message redelivery; authoritative task ownership is always fenced in the storage backend via
expected_retry_count.