Skip to main content

lapinbeam

CI Docs License: MIT

Real-time distributed systems framework for Python with a Rust core. An actor model inspired by Erlang/Elixir (BEAM), built with Rust (Tokio) exposed through PyO3.

Repository: https://github.com/rroblf01/lapinbeam · Docs: https://rroblf01.github.io/lapinbeam/ · Changelog

Status

1.3.0 — the public API (Node, Supervisor, actor/on, ActorRef/ RemoteRef, codec) is stable; a breaking change now requires a major version bump. This hasn't been run at production scale yet — see Limitations below for what it deliberately doesn't do.

Features

  • @actor decorated Python classes with async def receive(msg), or typed dispatch via @on(Type) / @on(default=True) (see below).
  • Supervisor with restart strategies (one_for_one, one_for_all, rest_for_one).
  • Node with transparent remote actor references.
  • Multiplexed TCP transport (one socket per peer) with bincode serialization.
  • Heartbeat and connection watchdog in the Rust core.
  • Automatic reconnection of desired peers with backoff.
  • Type-preserving payloads: @dataclass and Pydantic v2 models round-trip between nodes via lapinbeam.codec.
  • ask() request/response on top of fire-and-forget send(), and on_event() for connection/delivery/supervisor observability.
  • Optional shared-secret handshake authentication (cluster_secret).
  • Lightweight seed-node discovery (register_discovery/join_via_seeds) — a node needs one already-running node's address, not every node's.
  • Nested supervision trees: Supervisor.spawn_supervisor() lets a Supervisor supervise another Supervisor.
  • Bidirectional links (link/unlink/trap_exit) and one-way, non-lethal monitors (monitor/demonitor), local and cross-node, with no wire protocol changes for either.
  • Cluster-wide named process groups (join_group/leave_group/members) and cluster-wide unique name registration (register_name/ unregister_name/whereis_name), local and cross-node, with no wire protocol changes for either.
  • Supervisor.spawn_pool(): a fixed worker pool (function or @actor class handlers) with queue_capacity backpressure, key= sharding for per-key ordering, and executor="thread"|"process" for CPU-bound work; the returned PoolRef adds .map() (gather-and-collect over ask()) and .stop() (tears down just that pool), and spawn_pool() itself doubles as an async context manager. ActorRef.ask_stream()/MessageMeta.reply_stream()/reply_final() for streaming replies instead of one final answer.

Install

pip install lapinbeam

The wheel is built for abi3 >= 3.11, so a single artifact covers Python 3.11 through 3.14.

Quickstart (two nodes)

# terminal 1
NODE_NAME=node_a@127.0.0.1:9001 PEER=node_b@127.0.0.1:9002 uv run python examples/app_node_a.py
# terminal 2
NODE_NAME=node_b@127.0.0.1:9002 PEER=node_a@127.0.0.1:9001 uv run python examples/app_node_b.py

Or with Docker (validated end-to-end: 100/100 ACKs inside the compose network):

docker compose up --build

Typed message dispatch

By default an actor implements a single async def receive(self, msg). As an alternative, use @on(Type) to dispatch by the message's real type — which lapinbeam.codec already preserves for @dataclass/Pydantic payloads across nodes — and @on(default=True) for a catch-all handler:

from dataclasses import dataclass
from lapinbeam import actor, on


@dataclass
class Task:
    payload_id: int
    name: str


@actor(name="worker")
class Worker:
    @on(Task)
    async def handle_task(self, msg: Task):
        ...

    @on(default=True)
    async def handle_other(self, msg):
        print("unrecognized message:", msg)

An actor with any @on handler stops using receive entirely; a message whose type has no dedicated handler and no @on(default=True) fallback raises TypeError (crashing the actor, so Supervisor restarts it like any other unhandled exception). Actors that only define receive are unaffected.

Development

uv sync                       # create .venv, build the extension, install deps
uv run maturin develop        # fast rebuild of the Rust extension
uv run pytest                 # Python test suite
cargo test                    # Rust test suite
uv run python bench/bench_remote.py   # throughput benchmarks
uv run python bench/bench_latency.py  # RTT latency percentiles
uv run python bench/bench_codec.py    # codec + JSON conversion path, layer by layer
uv run python bench/bench_memory.py   # RSS under sustained load, connection churn, and mailbox backpressure
uv run python bench/bench_pool.py     # spawn_pool(): executor= CPU speedup, queue_capacity bounding, stop() cleanup

Nothing is installed on the OS: everything lives in .venv.

Documentation

Full docs (English + Spanish) live under docs/ and build with MkDocs + Material:

uv sync --group docs           # installs mkdocs, mkdocs-material, mkdocs-static-i18n
uv run mkdocs serve             # http://127.0.0.1:8000, live-reloads on edits
uv run mkdocs build --strict    # static site in site/ (gitignored)

Each page has an English file (e.g. docs/getting-started.md) and its Spanish translation (docs/getting-started.es.md); mkdocs-static-i18n serves the Spanish build under /es/ with a language switcher.

Benchmark snapshot

Measured on this machine (Python 3.14, loopback):

Metric Result
asyncio.Queue put/get ~1.6M msg/s
lapinbeam local send ~440K msg/s
lapinbeam remote (loopback TCP) throughput ~16K msg/s
Local dispatch RTT p50 0.007 ms
Remote loopback TCP RTT (send + ack) p50 0.44 ms / p99 0.93 ms

Limitations

  • Payloads must be JSON-compatible (dict/list/str/int/float/bool/None). Ints are limited to i64/u64; larger ints raise TypeError.
  • __lb_type__ is a reserved payload key (used by the type-preserving codecs).
  • Type preservation happens only on remote sends; local sends pass the object by reference (zero-copy). A Pydantic field typed loosely (e.g. Any) won't get a nested @dataclass value reconstructed on decode — it comes back as a plain dict instead; a properly-typed field (e.g. inner: Inner) round-trips fine via Pydantic's own validation.
  • Actor names must be unique per node — Supervisor.spawn() raises ValueError if the name is already registered to a different actor. Simultaneous dial (both nodes connecting to each other at once) is resolved deterministically — exactly one connection survives, not two.
  • No message persistence and no at-least-once delivery: a message in flight during a network partition is lost, not retried. See lapinbeam vs. Celery + RabbitMQ for what that means in practice.
  • Actor mailboxes are unbounded by default: an actor that can't keep up with its inbound rate has its mailbox grow without limit instead of applying backpressure. Pass Node(..., mailbox_capacity=N) to cap it — a full mailbox then drops new messages instead, firing on_event(kind="mailbox_full") (and, for a dropped remote send, an "error" event back on the sender).
  • Payloads larger than 16 MiB are rejected on the sender.

Publishing to PyPI

uv build produces a local wheel (abi3) + sdist in dist/ for testing, but the actual release is not a manual uv publish: pushing to main and then publishing a GitHub Release (which creates the matching vX.Y.Z tag) triggers .github/workflows/publish.yml — it re-runs the test suite, builds wheels for Linux (manylinux), macOS (x86_64 + arm64), and Windows via maturin-action, installs and smoke-tests each built wheel on its target OS, and only then publishes to PyPI via a Trusted Publisher (OIDC — no token stored anywhere).

CI (./.github/workflows/ci.yml) runs on every push/PR: the test matrix on Python 3.11-3.14, a Docker Compose end-to-end check, and a build of the distributable artifacts (not published from there).

Project layout

src/           Rust core (_core extension module)
lapinbeam/     Pure-Python layer (@actor, Node, Supervisor, refs)
tests/         Rust integration tests
tests-python/  Python tests (pytest)
examples/      Two-node bidirectional demo, a multi-node HTTP pipeline demo,
               a seed-node discovery demo, a supervision-tree/links/groups
               demo, a FastAPI+SSE+Postgres parallel-workload demo, plus
               E2E fixtures used by CI
bench/         Throughput, latency, codec, and memory benchmarks

License

MIT

Release files for lapinbeam 1.3.0

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

Source distribution (sdist)

Source distribution for lapinbeam 1.3.0
File Size Uploaded
lapinbeam-1.3.0.tar.gz 314.9 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for lapinbeam 1.3.0
File
lapinbeam-1.3.0-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
lapinbeam-1.3.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
lapinbeam-1.3.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
lapinbeam-1.3.0-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 4.6 MB

Release files / lapinbeam-1.3.0.tar.gz

Download URL lapinbeam-1.3.0.tar.gz
Size 314.9 kB
Tags Source
SHA-256 checksum
How to use checksums
6c57d5e5aaaf94b798bc73eec99a66e9d9339413f0cdb24c17d53b708763be48
BLAKE2b-256 checksum
How to use checksums
5a97c534c821bc92695e1fbd07a285ba35fe0106bc518b0ed68757267dc7a002
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 Aug 20, 2026.

Transparency log

Release files / lapinbeam-1.3.0-cp311-abi3-win_amd64.whl

Download URL lapinbeam-1.3.0-cp311-abi3-win_amd64.whl
Size 980.5 kB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
c35dfcac7a519b3d7361f3ac8d5179ec1b6338305c369c2fb1c9ac3157fb5489
BLAKE2b-256 checksum
How to use checksums
abcc7015228efddb9e30e3ff9e88b144e8db6b1ee3cb6dfc8866d53baa7b375a
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 Aug 20, 2026.

Transparency log

Release files / lapinbeam-1.3.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL lapinbeam-1.3.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.2 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
93b8d17c661b44194e9db700f5d62bd629019a77879c824b160579e75294062f
BLAKE2b-256 checksum
How to use checksums
a5c7c2b15056a2925db554648d6e75f64907e242bd57044f7c4c67f36a50b0b0
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 Aug 20, 2026.

Transparency log

Release files / lapinbeam-1.3.0-cp311-abi3-macosx_11_0_arm64.whl

Download URL lapinbeam-1.3.0-cp311-abi3-macosx_11_0_arm64.whl
Size 1.1 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c57e8957217c8073dd06ad005dd8ddc7584341ea9983070904b68bf0d5576848
BLAKE2b-256 checksum
How to use checksums
7b49a690d0178d40578818964cbc20a31d5babfd72384dd3cf3c23fd153b6375
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 Aug 20, 2026.

Transparency log

Release files / lapinbeam-1.3.0-cp311-abi3-macosx_10_12_x86_64.whl

Download URL lapinbeam-1.3.0-cp311-abi3-macosx_10_12_x86_64.whl
Size 1.1 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
217eef6be92d1d077b3abb98ccf6109fa0b50326c948c1fb42395a9da2adcb70
BLAKE2b-256 checksum
How to use checksums
801a40769f7f1f11e81c49832311408178105ba5a75eb442d4e09e1c86d3201a
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 Aug 20, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.3.0 This release

5 release files

1.2.0

5 release files

1.0.3

5 release files

1.0.2

5 release files

1.0.1

5 release files

1.0.0

5 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