Skip to main content

General-purpose ZeroMQ communication node with pub/sub, request/reply, registry, heartbeats, stats, and diagnostics

Project description

intrabus

intrabus is a lightweight, general-purpose ZeroMQ communication node for Python applications.

It gives independent modules a simple way to communicate over:

  • publish/subscribe events
  • request/reply messages
  • module registration
  • heartbeats and liveness tracking
  • runtime statistics
  • diagnostics
  • node health queries

The goal is to keep setup simple: install the library, start a CommunicationNode, connect modules with BusInterface, and communicate.

pip install intrabus

Current release target: 0.2.0

intrabus is still alpha software. The public API is usable, but the project may still evolve before 1.0.


Why intrabus?

Use intrabus when you want multiple Python components to communicate inside one machine or between local processes without deploying external infrastructure such as Redis, RabbitMQ, Kafka, or HTTP services.

Typical use cases:

  • test automation systems
  • modular desktop applications
  • robotics or hardware-control tools
  • local monitoring/control systems
  • plugin-like Python applications
  • prototypes that may later grow into distributed systems

intrabus is not intended to replace large production message brokers. It is designed to be small, embeddable, and easy to reason about.


Quick start

from intrabus import BusInterface, CommunicationNode


def handle_request(message: dict) -> dict:
    return {
        "pong": True,
        "received": message,
    }


with CommunicationNode("local"):
    server = BusInterface("server", request_handler=handle_request)
    client = BusInterface("client")

    reply = client.send_request("server", {"ping": True}, timeout=2)
    print(reply)

    health = client.send_request(
        "intrabus.node",
        {"command": "node.get_health"},
        timeout=2,
    )
    print(health["status"])

    server.stop()
    client.stop()

Core concepts

CommunicationNode

CommunicationNode owns the core intrabus runtime:

  • TopicBroker for pub/sub traffic
  • CentralBroker for request/reply traffic
  • ModuleRegistry for known modules
  • StatsCollector for runtime metrics
  • DiagnosticsManager for runtime diagnostics

Most users should start here:

from intrabus import CommunicationNode

with CommunicationNode("local") as node:
    print(node.is_running)

BusInterface

BusInterface is what application modules use to communicate.

from intrabus import BusInterface

module = BusInterface("sensor")

A BusInterface can:

  • publish events
  • subscribe to events
  • send requests
  • handle incoming requests
  • auto-register with the local node
  • send heartbeats to the local node

Module registry

When a module starts, it can automatically register with the node:

worker = BusInterface("worker")

The node tracks:

  • module name
  • node ID
  • status: online or offline
  • connected time
  • last seen time
  • capabilities
  • metadata

Heartbeats and stale detection

By default, modules send periodic heartbeats to the node.

The node can mark modules offline when they stop sending heartbeats:

reply = client.send_request(
    "intrabus.node",
    {
        "command": "node.get_health",
        "timeoutSeconds": 5,
    },
)

Publish/subscribe

from intrabus import BusInterface, CommunicationNode


with CommunicationNode():
    publisher = BusInterface("publisher")
    subscriber = BusInterface("subscriber")

    def on_temperature(topic: str, message: dict) -> None:
        print(topic, message)

    subscriber.subscribe("temperature", on_temperature)
    publisher.publish("temperature", {"value": 23.5})

    publisher.stop()
    subscriber.stop()

Request/reply

from intrabus import BusInterface, CommunicationNode


def echo(message: dict) -> dict:
    return {"echo": message}


with CommunicationNode():
    server = BusInterface("server", request_handler=echo)
    client = BusInterface("client")

    reply = client.send_request("server", {"hello": "world"}, timeout=2)
    print(reply)

    server.stop()
    client.stop()

Node management commands

The internal node service is available at:

intrabus.node

Send requests to it with BusInterface.send_request().

node.get_registry

Returns the current module registry.

client.send_request("intrabus.node", {"command": "node.get_registry"})

node.get_stats

Returns current runtime statistics.

client.send_request("intrabus.node", {"command": "node.get_stats"})

node.get_diagnostics

Returns current diagnostics derived from registry and stats.

client.send_request("intrabus.node", {"command": "node.get_diagnostics"})

node.get_health

Returns a combined node health payload:

client.send_request(
    "intrabus.node",
    {
        "command": "node.get_health",
        "timeoutSeconds": 5,
    },
)

The health response contains:

{
    "ok": True,
    "nodeId": "local",
    "status": "healthy",  # healthy | degraded | unhealthy
    "staleModules": [],
    "registry": {...},
    "stats": {...},
    "diagnostics": {...},
}

node.reset_stats

Clears runtime statistics.

client.send_request("intrabus.node", {"command": "node.reset_stats"})

node.clear_diagnostics

Clears currently stored diagnostics.

client.send_request("intrabus.node", {"command": "node.clear_diagnostics"})

Backward-compatible node commands

The following older command names are still supported:

Older command Preferred command
registry.get node.get_registry
stats.get node.get_stats
diagnostics.get node.get_diagnostics
stats.reset node.reset_stats
diagnostics.clear node.clear_diagnostics

Internal module lifecycle commands are also supported:

  • module.register
  • module.unregister
  • module.heartbeat
  • registry.health

Most application code should use the node.* commands.


Runtime statistics

StatsCollector tracks bounded in-memory runtime statistics:

  • total messages
  • requests
  • replies
  • events
  • timeouts
  • errors
  • delivery failures
  • latency samples
  • average latency
  • max latency
  • per-module stats
  • per-topic stats
  • recent events
  • recent message metadata

Recent messages are bounded and do not include full payloads by default. This avoids unbounded RAM growth and reduces the risk of accidentally storing sensitive data.


Diagnostics

DiagnosticsManager currently derives diagnostics from registry and stats.

Supported diagnostic codes:

Code Meaning
MODULE_OFFLINE A registered module is offline
REQUEST_TIMEOUT A request timed out
HANDLER_ERROR A request handler raised an exception
DELIVERY_FAILURE A message could not be delivered by the broker

Diagnostic severities:

  • info
  • warning
  • error
  • critical

node.get_health maps diagnostics to node status:

Status Meaning
healthy No warnings or errors
degraded At least one warning
unhealthy At least one error or critical diagnostic

MessageEnvelope

MessageEnvelope is a dataclass for future-compatible standardized messages.

It includes fields for future multi-node support:

  • messageId
  • correlationId
  • sender
  • target
  • topic
  • sourceNode
  • targetNode
  • ttl
  • hopPath
  • payload

The current brokers still use lightweight JSON payloads internally, but MessageEnvelope is available as the standard message shape for higher-level integrations.


Advanced: manual brokers

Most users should use CommunicationNode.

For low-level control, you can still start brokers manually:

from intrabus import run_central_broker, run_topic_broker

run_topic_broker()
run_central_broker()

And stop singleton brokers:

from intrabus import stop_central_broker, stop_topic_broker

stop_topic_broker()
stop_central_broker()

This is mainly useful for simple scripts and compatibility with older examples.


Development

Install development dependencies:

uv sync --dev

Run tests:

uv run pytest -q

Run linting and formatting checks:

uv run ruff check .
uv run ruff format --check .

Format code:

uv run ruff format .

Build the package:

uv run python -m build

Check distributions:

uv run twine check dist/*

Roadmap

Planned future work:

  • event/message sinks for streaming to external consumers
  • demo project using this package
  • monitoring dashboard as a separate project
  • richer diagnostics
  • multi-node routing
  • optional dashboard/websocket integrations

The library itself will stay focused on being a general-purpose communication node.


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

intrabus-0.2.0.tar.gz (55.2 kB view details)

Uploaded Source

Built Distribution

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

intrabus-0.2.0-py3-none-any.whl (20.2 kB view details)

Uploaded Python 3

File details

Details for the file intrabus-0.2.0.tar.gz.

File metadata

  • Download URL: intrabus-0.2.0.tar.gz
  • Upload date:
  • Size: 55.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for intrabus-0.2.0.tar.gz
Algorithm Hash digest
SHA256 cbafcd3cfa43f0c740b18e616100c9e1ce1c7689cb4dee1e1036b1364979c26c
MD5 3d80504e0fa46b245221f46fc57682b9
BLAKE2b-256 b48f28701972e71c61171efef49140d37ad8930f722d1ab70175fc5399d78925

See more details on using hashes here.

Provenance

The following attestation bundles were made for intrabus-0.2.0.tar.gz:

Publisher: publish.yaml on BuilderCrafter/intrabus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file intrabus-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: intrabus-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 20.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for intrabus-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 92ec1a281cdb1a4bb1276798e1dd3dca0baf13962daa1afbc57001e2f33d4c12
MD5 4438fdd8bd2da13486ed6dec431efeb5
BLAKE2b-256 67b6bd516ad90407b68682349b3a0f41bf8e97d1c5b042d959bb6078b85c7b50

See more details on using hashes here.

Provenance

The following attestation bundles were made for intrabus-0.2.0-py3-none-any.whl:

Publisher: publish.yaml on BuilderCrafter/intrabus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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