Skip to main content

resonate-base

The connector seam behind the Resonate Python SDK and every Resonate connector.

resonate-base holds what you need to put Resonate on a new substrate, and nothing else. A connector's job is to move opaque strings and to decide where they go. Everything else — promise ids, delivery-address conventions, codec, context, core, retry, timing, the observability stream, the wire records, the transport, and the SDK's own error vocabulary — stays in resonate-sdk.

It has no third-party dependencies and never imports the SDK, so a connector built on it is independent of the SDK's release cadence.

What's in it

Module What it gives a connector
resonate_base.connections Network and Source — the two protocols to implement
resonate_base.error ConnectorError, the one error a connector raises
resonate_base.PROTOCOL_VERSION The wire protocol version

That is the whole package. There is no framework here and nothing to conform to — implement the protocols however suits your substrate.

Building a connector

from resonate_base import ConnectorError


class MyConnection:
    """A Network and Source over some new substrate."""

    # -- Network: request/response ------------------------------------------
    async def send(self, req: str, origin: str) -> str:
        try:
            return await self._rpc(self._partition_for(origin), req)
        except OSError as exc:
            raise ConnectorError(exc) from exc

    # -- Source: push -------------------------------------------------------
    def unicast(self) -> str: ...
    def resolve_target(self, target: str) -> str: ...
    def recv(self, callback) -> None: ...

    # -- both ---------------------------------------------------------------
    async def start(self) -> None: ...
    async def stop(self) -> None: ...

Implement Network, Source, or both — a single connection can serve as both halves (resonate-nats does).

Routing a request: origin

send receives the request and the origin it routes by: the lineage the request acts on, which is what selects the server's origin-state partition. A substrate that shards needs it; one that posts everything to a single endpoint ignores it.

It arrives as an argument on purpose. Digging it out of the payload would mean knowing both the envelope layout and the promise id format — two SDK-internal formats free to change under you. The SDK owns both, so the SDK resolves it and hands it over. Two things follow: req is opaque, so you never parse it, and every request has an origin, so there is no "unrouted" case.

Addressing: unicast and resolve_target

A source advertises two things, and it chooses the shape of both:

  • unicast() — where the server should push messages meant for this process alone. Handed to the server verbatim when a listener is registered.
  • resolve_target(target) — where the work this process dispatches to a named group should be delivered.

The server parses an address with Go's url.Parse, dispatches on the scheme, and hands the rest straight back to you. So resonate-nats advertises nats://resonate.recv.workers.7f3a — a NATS subject already is an address in the NATS namespace, and nesting a second addressing scheme inside it would buy nothing.

The one trap: Go lowercases the URL host, so an uppercase host does not round trip — and nothing raises. The server accepts the address, stores it, and the message is simply never delivered.

Sources are optional. A process that only sends (an HTTP handler, a serverless function) implements Network alone.

Errors

ConnectorError is all a connector needs. The SDK's outermost catch is except ResonateError, so a transport that raises a bare OSError through send kills the worker instead of releasing the task — wrap it.

Subclassing is optional. Do it when your connector ships as its own distribution and its users benefit from a name they can catch specifically:

class NatsError(ConnectorError): ...

Add nothing else — the wrapped cause, the args tuple (and so the pickle round-trip the codec depends on), and the message shape are all inherited, so there is no __init__ to forget to forward.

Either way, application code can handle any transport failure without importing your package:

from resonate_base import ConnectorError

try:
    await resonate.run("greet", ...)
except ConnectorError as exc:
    ...

That is what lets the SDK's SenderError union stay closed and exhaustively type-checked while the set of connectors stays open.

Installing

Application code should depend on resonate-sdk, which depends on this package. Install resonate-base directly only when building a connector.

Release files for resonate-base 0.8.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 resonate-base 0.8.0
File Size Uploaded
resonate_base-0.8.0.tar.gz 4.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for resonate-base 0.8.0
File Interpreter ABI Platform
resonate_base-0.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 11.8 kB

Release files / resonate_base-0.8.0.tar.gz

Download URL resonate_base-0.8.0.tar.gz
Size 4.9 kB
Tags Source
SHA-256 checksum
How to use checksums
781cd7b0569c3fb4c3d66cd114b3afb058b34ec38007bcc749fa02ff422de124
BLAKE2b-256 checksum
How to use checksums
7a2c5b3af0fd0a395920a87a09821e854fc73bc609ca4d4728bcd670a80f7c6e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / resonate_base-0.8.0-py3-none-any.whl

Download URL resonate_base-0.8.0-py3-none-any.whl
Size 6.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
76d045c5661c48550c0ea346dfb90d6703f080cc3aeed9b7e52b942467486847
BLAKE2b-256 checksum
How to use checksums
833657f06300c9f5acf890e9caa592247826d6b7b2183e1cb5ac73684c0d5a8a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.8.0 This release

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