Skip to main content

Rembus for Python

Docs Stable Docs Dev Build Status Coverage

Rembus is a Pub/Sub and RPC middleware.

Features

  • Binary message encoding using CBOR.

  • Native support for exchanging DataFrames.

  • Persistent storage via DuckDB DuckLake.

  • Pub/Sub QOS0, QOS1 and QOS2.

  • Hierarchical topic routing with wildcards (*/*/temperature).

  • MQTT integration.

  • WebSocket transport.

See Rembus.jl broker for a full fledged broker that supports WebSocket, ZMQ and plain tcp protocols and more features like private topics, multi-tenancy and more.

Concepts

  • Component: an addressable node in a distributed system. A component connects to a broker and communicates using Pub/Sub and/or RPC semantics.

  • Broker: a specialized component responsible for routing Pub/Sub messages and dispatching RPC calls between components. A broker may also persist messages and expose services.

  • Topic: a "logical channel" string identifier used for Pub/Sub message routing (e.g. alarm_topic).

  • Topic space: a set of topics defined by wildcard patterns (e.g. */telemetry) used for bulk subscription..

  • Subscription: a callback bound to a topic or topic space; invoked automatically with the message payload when a Pub/Sub message is published. Supports wildcard topics and optional delivery of messages sent while the subscriber was offline (msgfrom=rb.LastReceived).

  • RPC Service: a named function exposed by a component and registered at the broker for remote invocation.

  • RPC Call: a synchronous or asynchronous request issued by a component to invoke a remote RPC service.

  • Schema: an optional declarative mapping between topic patterns and persistent storage tables, used to structure and persist messages at rest.

  • Data at Rest: broker capability to persist published messages into DuckDB tables defined by a schema, enabling historical queries and analytics.

Getting Started

Install the package:

pip install rembus

Broker

Start a broker (sync or async):

import rembus as rb

# sync version
bro = rb.node() # equivalent to rb.node(port = 8338)
bro.wait() # event loop, not needed in interactive interpreter


# async version
bro = await rb.component()
await bro.wait() 

Broker with persistent storage

A Rembus broker can be configured with a schema to persist published messages into a DuckDB database via the DataLake extension.

A schema declaratively maps Pub/Sub topic patterns to relational tables. Topics variables are extracted from the topic path and mapped to table columns; message payload fields are mapped to the remaining columns.

Example schema.json:

{
    "tables": [
        {
            "table": "sensor",
            "topic": ":site/:type/:dn/sensor",
            "columns": [
                {"col": "site", "type": "TEXT", "nullable": false},
                {"col": "type", "type": "TEXT", "nullable": false},
                {"col": "dn", "type": "TEXT"}
            ],
            "keys": ["dn"]
        },
        {
            "table": "telemetry",
            "topic": ":dn/telemetry",
            "columns": [
                {"col": "dn", "type": "TEXT"},
                {"col": "temperature", "type": "DOUBLE"},
                {"col": "pressure", "type": "DOUBLE"}
            ],
            "extras": {
                "recv_ts": "ts",
                "slot": "time_bucket"
            }
        }
    ]
}

Schema semantics

  • Each entry in tables defines a topic-to-table binding.

  • Topic segments prefixed with : are variables extracted from the topic path and written to the corresponding columns.

  • Message payload fields are mapped positionally or by name to remaining columns.

  • keys define logical primary keys.

  • extras specify broker-generated metadata (e.g. receive timestamp, time bucketing).

Example mappings

  • Messages published to :site/:type/:dn/sensor are persisted in the sensor table, with site, type, and dn derived from the topic path.

  • Messages published to :dn/telemetry are persisted in the telemetry table, with metric values extracted from the message payload.

If a schema is provided, DuckLake tables are created automatically if they do not already exist, and all matching publications are persisted.

For each table three special topics for RPC services are automatically created:

  • upsert_<table> insert/update records;
  • query_<table> retrieve records;
  • delete_<table> remove records;

RPC calls to query_* topics return a Polars DataFrame.

For example:

cli.rpc("query_sensor", {"where": "type='HVAC'"})

Starting a broker with storage enabled

import rembus as rb

bro = await rb.component(schema="schema.json")
await bro.wait() 

Components

Connect to a Broker:

# named component
cli = await rb.component("ws://host:8338/myname")

# default host/port
cli = await rb.component("myname")

# anonymous
cli = await rb.component(rb.anonym(host="host", port=8338))

Why named components

  • Enables authentication (RSA/ECDSA/shared secret).

  • Allows persistent twin mapping; offline messages are buffered. A Component connects to a Broker using a URL-like formatted string that identifies the broker address and declare the name of the Component.

Pub/Sub

Publish

# Single message
await cli.publish("site/type/dn/sensor")
await cli.publish("dn/telemetry", {'temperature': 21.6, 'pressure': 980})

# DataFrame
import polars as pl
df = pl.DataFrame({"dn":["s1","s2"], "temperature":[15,18.8]})
await cli.publish("telemetry", df)

Subscribe

# Single topic
def alarm(slogan, severity):
    print(f"{slogan}: {severity}")

sub = rb.node("monitor")
sub.subscribe(alarm, topic="alarm") # equivalent to sub.subscribe(alarm)

# Topic space
def telemetry(topic, data):
    print(f"{topic}: {data}")

sub.subscribe(telemetry, topic="**/telemetry", msgfrom=rb.LastReceived)

The subscribed alarm function gets called with the using the message payload: slogan as first argument and severity as second argument:

cli.publish("alarm", "mydevice: battery very low", "CRITICAL")

The option msgfrom is for receiving published messages when the component was not subscribed to the topic, for example because it was not connected when the messages was published.

RPC

Expose

import rembus as rb

def add(x,y):
    return x+y

handle = rb.node('calculator')
handle.expose(add)
handle.wait()

Call

import rembus as rb

handle = rb.node("myclient")
result = handle.rpc('add', 1, 2)

Metadata

Release files for rembus 0.8.20

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rembus 0.8.20
File Size Uploaded
rembus-0.8.20.tar.gz 64.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rembus 0.8.20
File Interpreter ABI Platform
rembus-0.8.20-py3-none-any.whl Python 3 none any Details

Total release size: 131.0 kB

Release files / rembus-0.8.20.tar.gz

Download URL rembus-0.8.20.tar.gz
Size 64.5 kB
Tags Source
SHA-256 checksum
How to use checksums
3ea5d908d9d05a4132610cd479efc90df884151af3a1c81e26e352518c2e0527
BLAKE2b-256 checksum
How to use checksums
65e3a74481e0988f9030df558c534a3c83ddc0cbd49481f09548e81901d05698
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / rembus-0.8.20-py3-none-any.whl

Download URL rembus-0.8.20-py3-none-any.whl
Size 66.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e8cb06b8f5709a9a2887f8e72b47a81edac765467a2cf935de723a388714a39b
BLAKE2b-256 checksum
How to use checksums
66dc5127ab363887f3fec42498a85669b8854535245a18fae29f4dac7362f8b3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.8.23

2 release files

This release

0.8.20 This release

2 release files

0.8.19

2 release files

0.8.18

2 release files

0.8.17

2 release files

0.8.15

2 release files

0.8.14

2 release files

0.8.13

2 release files

0.8.10

2 release files

0.8.9

2 release files

0.8.8

2 release files

0.8.7

2 release files

0.8.6

2 release files

0.8.5

2 release files

0.8.4

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.5

2 release files

0.1.0

2 release files

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