Skip to main content

Weni EDA

weni-eda is a Python library that simplifies Event-Driven Architecture (EDA) with Django and AMQP brokers. It supports:

Broker SSL Params factory Env prefix
RabbitMQ No ConnectionParamsFactory EDA_*
AmazonMQ Yes (port 5671) AMQConnectionParamsFactory AMQ_*

Both scopes share the same consumer and publisher APIs — you only swap the connection params factory (and the matching env vars).

Features

  • Easy integration with Django
  • RabbitMQ (plain AMQP) and AmazonMQ (AMQP over SSL)
  • Transport-agnostic Message and Channel abstractions
  • Optional event envelopes (event_id, event_type, producer, timestamp, data)
  • Optional buffered consumers for high-throughput workloads

Installation

pip install weni-eda

Django setup

Add the app to INSTALLED_APPS:

# settings.py
INSTALLED_APPS = [
    # ...
    "weni.eda.django.eda_app",
]

Point EDA_CONSUMERS_HANDLE to the function that registers your consumers (used by both brokers unless overridden per process):

# settings.py
EDA_CONSUMERS_HANDLE = "myapp.messages.handle.handle_consumers"

RabbitMQ (no SSL)

Use this for a standard RabbitMQ broker on port 5672.

Environment variables

Variable Example Description
EDA_BROKER_HOST "localhost" Broker hostname or IP
EDA_BROKER_PORT 5672 Broker port
EDA_BROKER_USER "guest" Username
EDA_BROKER_PASSWORD "guest" Password
EDA_VIRTUAL_HOST "/" Virtual host
EDA_PRODUCER "weni-engine" Producer name included in event envelopes
EDA_CONSUMERS_HANDLE "myapp.messages.handle.handle_consumers" Consumer registration function

Publisher

from weni.eda.django import ConnectionParamsFactory
from weni.eda.eda_publisher import EDAPublisher

publisher = EDAPublisher(ConnectionParamsFactory)
publisher.send_message(
    {"event": "order.created", "order_id": 123},
    exchange="orders",
    routing_key="order.created",
)

ConnectionParamsFactory reads the EDA_* settings above.

Consumer

  1. Implement a consumer:
from weni.eda.django.consumers import EDAConsumer
from weni.eda.messages import Message


class ExampleConsumer(EDAConsumer):
    def consume(self, message: Message):
        body = message.json()
        # ... handle body ...
        self.ack()
  1. Register it in handle_consumers:
from weni.eda.channels import Channel
from .example_consumer import ExampleConsumer


def handle_consumers(channel: Channel):
    channel.basic_consume("example-queue", callback=ExampleConsumer().handle)
  1. Start consuming (default params factory = RabbitMQ / no SSL):
python manage.py edaconsume

AmazonMQ (SSL)

Use this for AmazonMQ (or any AMQP broker that requires TLS). Connections use SSL on port 5671 via AMQConnectionParamsFactory.

Environment variables

Variable Example Description
AMQ_BROKER_HOST "b-xxxx.mq.us-east-1.amazonaws.com" Broker hostname
AMQ_BROKER_PORT 5671 SSL port (default 5671)
AMQ_BROKER_USER "myuser" Username
AMQ_BROKER_PASSWORD "mypassword" Password
AMQ_VIRTUAL_HOST "/" Virtual host
AMQ_BROKER_HEARTBEAT 300 Heartbeat interval in seconds (default 300)
AMQ_BROKER_SSL_SERVER_HOSTNAME "b-xxxx.mq.us-east-1.amazonaws.com" Hostname for SSL certificate verification / SNI (defaults to AMQ_BROKER_HOST)

You still need EDA_CONSUMERS_HANDLE (or --handle) so the process knows which consumers to register.

Publisher

from weni.eda.django import AMQConnectionParamsFactory
from weni.eda.eda_publisher import EDAPublisher

publisher = EDAPublisher(AMQConnectionParamsFactory)
publisher.send_message(
    {"event": "order.created", "order_id": 123},
    exchange="orders",
    routing_key="order.created",
)

AMQConnectionParamsFactory reads the AMQ_* settings and enables SSL automatically.

Consumer

Consumers and handle_consumers are identical to RabbitMQ. The only difference is which params factory you pass when starting the process:

python manage.py edaconsume \
  --params-class "weni.eda.django.AMQConnectionParamsFactory"

Event envelopes (optional)

By default send_message publishes the body as-is (backward compatible). Pass event_type to wrap the payload in a standardized envelope:

{
  "event_id": "c6b84b6c-1da4-4c4c-83b6-2c97441584c0",
  "event_type": "project.updated",
  "producer": "weni-engine",
  "timestamp": "2026-05-20T11:15:00Z",
  "data": {
    "uuid": "8e7d8a",
    "name": "Novo Nome do Projeto",
    "user_id": "owner@example.com",
    "updated_fields": ["name"]
  }
}
Field Source
event_id Generated UUID
event_type Passed by the caller via event_type=
producer EDA_PRODUCER env var (or explicit override via Event.build)
timestamp UTC ISO 8601 with Z suffix
data Original body dict

Publisher

publisher.send_message(
    {"uuid": "8e7d8a", "name": "Novo Nome do Projeto"},
    exchange="projects",
    routing_key="project.updated",
    event_type="project.updated",
)

Consumer

class ProjectUpdatedConsumer(EDAConsumer):
    def consume(self, message: Message):
        event = message.event()
        # event.event_id, event.event_type, event.producer, event.timestamp
        payload = event.data  # or message.data()
        self.ack()

Legacy consumers that call message.json() keep working for raw (non-envelope) messages.

Event API

Method / attribute Description
Event.build(event_type, data, producer=None) Build a new envelope (event_id + timestamp generated)
event.to_dict() Serialize to the envelope dict
Event(**payload) Reconstruct from a received envelope dict

Consumers reference

Message API

Consumers receive a weni.eda.messages.Message (transport-agnostic — no need to import amqp):

Method / attribute Description
message.body Raw body (bytes)
message.json(encoding="utf-8") Parse body as JSON → dict
message.event(encoding="utf-8") Parse body as event envelope → Event
message.data(encoding="utf-8") Return event.data from an event envelope
self.ack() Ack the message (remove from queue)
message.reject(requeue=False) Reject the message (called automatically if consume raises)

If consume raises, the message is rejected and the error is logged.

Channel API

handle_consumers receives a weni.eda.channels.Channel:

Method Description
channel.basic_consume(queue, callback=...) Register a queue consumer
channel.basic_qos(...) Set prefetch limits before consuming

edaconsume flags

Useful when one project talks to both brokers (or multiple consumer groups):

python manage.py edaconsume \
  --handle "myapp.messages.handle.handle_consumers" \
  --backend "weni.eda.backends.pyamqp_flush_backend.PyAMQPFlushConnectionBackend" \
  --params-class "weni.eda.django.AMQConnectionParamsFactory"
Flag Default Description
--params-class ConnectionParamsFactory (RabbitMQ) Dotted path to the params factory
--handle settings.EDA_CONSUMERS_HANDLE Dotted path to handle_consumers(channel)
--backend settings.EDA_CONNECTION_BACKEND or PyAMQPConnectionBackend Connection backend

Quick reference:

# RabbitMQ (no SSL)
python manage.py edaconsume

# AmazonMQ (SSL)
python manage.py edaconsume --params-class "weni.eda.django.AMQConnectionParamsFactory"

Buffered consumers (optional)

By default each consumer acks messages one by one. For high-throughput workloads that batch DB writes, use PyAMQPFlushConnectionBackend.

Your handle_consumers must register consumers and return an iterable of flushable objects, each exposing:

  • flush() — persist and ack buffered work
  • flush_interval (optional float) — max seconds between flushes (default 1.0)
from weni.eda.backends.pyamqp_flush_backend import PyAMQPFlushConnectionBackend
from weni.eda.channels import Channel
from weni.eda.django import AMQConnectionParamsFactory


def handle_consumers(channel: Channel):
    consumer = BufferedConsumer()  # exposes flush() and flush_interval
    consumer.setup(channel)        # channel.basic_qos(...) + channel.basic_consume(...)
    return [consumer]


def run():
    params = AMQConnectionParamsFactory.get_params()
    PyAMQPFlushConnectionBackend(handle_consumers).start_consuming(params)

Or via the management command:

python manage.py edaconsume \
  --backend "weni.eda.backends.pyamqp_flush_backend.PyAMQPFlushConnectionBackend" \
  --params-class "weni.eda.django.AMQConnectionParamsFactory"

Returning None (or an empty iterable) disables periodic flushing. You can also set settings.EDA_CONNECTION_BACKEND.

Both backends use Python logging for connection lifecycle and errors — configure handlers in your Django app (or Sentry) as needed.


License

This project is licensed under the Mozilla Public License 2.0. See the LICENSE file for the full text.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

weni_eda-0.3.0.tar.gz (23.0 kB view details)

Uploaded Source

Built Distribution

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

weni_eda-0.3.0-py3-none-any.whl (33.2 kB view details)

Uploaded Python 3

File details

Details for the file weni_eda-0.3.0.tar.gz.

File metadata

  • Download URL: weni_eda-0.3.0.tar.gz
  • Upload date:
  • Size: 23.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.10.19 Darwin/25.5.0

File hashes

Hashes for weni_eda-0.3.0.tar.gz
Algorithm Hash digest
SHA256 86b87c1646518a7b10ff782f499d68b22b4d7f76e11084a6450aa31d15d9326d
MD5 158c7ee6d27dd07345de26cfff374093
BLAKE2b-256 b0538f7532279bbb3b4c20f51e063efc3940d91a11c504ad231f7d29ed4dc04c

See more details on using hashes here.

File details

Details for the file weni_eda-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: weni_eda-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 33.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.10.19 Darwin/25.5.0

File hashes

Hashes for weni_eda-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ed4b5bafb0e34b5bf3b597d9ae9ff5621bd6ee591baf7ddbf592df58510dc7c7
MD5 28c80d840e6804dc14bc05afebec368e
BLAKE2b-256 80fc4671460671ffaf74cedec0f5b86a2110f0bdd3a48b2a0fd9df3a0d276ae3

See more details on using hashes here.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page