Skip to main content

CI

bluesky-nats

bluesky-nats connects Bluesky document streams to NATS JetStream.

It supports two primary workflows:

  • publish Bluesky documents from a RunEngine to JetStream subjects
  • consume JetStream subjects and dispatch documents to Bluesky callbacks

Who this is for

Use this package if you want to move Bluesky documents across processes or hosts using NATS JetStream while preserving document semantics.

Installation

Install from PyPI:

uv add bluesky-nats

Install with optional dependencies used by the examples:

uv add bluesky-nats --extra examples

Python support: >=3.11,<3.15

Prerequisites

You need a NATS server with JetStream enabled and a stream configured for your subject pattern (for example events.>).

By default, this package uses stream name bluesky.

For local setup, use the provided Docker assets:

  • docker/compose.yaml
  • docker/Readme.adoc (includes stream creation commands)

Quick start (local)

  1. Start NATS JetStream (from this repository root):

    cd docker
    docker compose up -d
    
  2. Ensure a JetStream named bluesky exists and is bound to events.>. See docker/Readme.adoc for exact commands.

  3. In a separate shell from repository root, run examples:

    uv run python examples/print_subscriber.py
    uv run python examples/publisher.py
    
  4. You should see published documents printed by the subscriber.

Minimal publisher example

Attach NATSPublisher to a RunEngine and publish documents:

import atexit

from bluesky.run_engine import RunEngine

from bluesky_nats.nats_client import NATSClientConfig, connect_sync
from bluesky_nats.nats_executor import AsyncPublishManager, CoroutineExecutor
from bluesky_nats.nats_publisher import NATSPublisher

if __name__ == "__main__":
    RE = RunEngine({})
    config = NATSClientConfig(servers=["nats://localhost:4222"])
    executor = CoroutineExecutor()
    client, js = connect_sync(executor, config)

    manager = AsyncPublishManager(executor, client, strict_publish=True)
    nats_publisher = NATSPublisher(
        manager=manager,
        js=js,
        subject_factory="events.nats-bluesky",
    )

    if not client.is_connected:
        raise RuntimeError("NATS connection is required before starting plans")

    RE.subscribe(nats_publisher)

    # Optional: expose current publisher status snapshot
    print(nats_publisher.health)

    # Optional: register lifecycle cleanup (useful for interactive sessions)
    atexit.register(
        nats_publisher.shutdown_callback(timeout=10, shutdown_executor=True)
    )

Minimal dispatcher/consumer example

Consume subjects and forward documents to a callback:

import asyncio

from bluesky_nats.nats_dispatcher import NATSDispatcher


async def main() -> None:
    async with NATSDispatcher(subject="events.>") as dispatcher:
        dispatcher.subscribe(print)
        await asyncio.sleep(60)


if __name__ == "__main__":
    asyncio.run(main())

Configuration

  • Client connectivity is configured through NATSClientConfig.
  • Publisher subjects are derived as <subject_factory>.<document_name>.
  • Publisher does not pick a stream explicitly; the server maps subjects to streams, while JetStream publish acknowledgements confirm server receipt.
  • strict_publish=True on AsyncPublishManager enables fail-fast behavior: async publish failures are latched and raised on subsequent callback calls.
  • publisher.health returns a PublisherHealth snapshot (connectivity, pending publishes, last error/ack, and last subject).
  • publisher.shutdown_callback(...) returns a zero-arg callable suitable for atexit.register(...).

Strict mode

Use strict mode when message delivery is mandatory for your architecture.

  • Set strict_publish=True on AsyncPublishManager.
  • Check client.is_connected before running plans to gate execution.
  • If an async publish fails later, strict mode raises RuntimeError from the callback path so the RunEngine can fail fast.

See the examples/ directory for complete runnable scripts.

Troubleshooting

  • NoStreamResponseError: the target stream does not exist or does not match your subject pattern.
  • Subscriber receives nothing: verify publisher and dispatcher subjects are compatible (for example events.nats-bluesky vs events.>).
  • Connection failures: check server URL/port and whether JetStream is enabled.

Metadata

Release files for bluesky-nats 2.0.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 bluesky-nats 2.0.0
File Size Uploaded Provenance Actions
bluesky_nats-2.0.0.tar.gz 189.6 kB Without provenance Details for bluesky_nats-2.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for bluesky-nats 2.0.0
File Interpreter ABI Platform Actions
bluesky_nats-2.0.0-py3-none-any.whl Python 3 none any Details for bluesky_nats-2.0.0-py3-none-any.whl

Total release size: 228.3 kB

Release files / bluesky_nats-2.0.0.tar.gz

Download URL bluesky_nats-2.0.0.tar.gz
Size 189.6 kB
Tags Source
SHA-256 checksum
How to use checksums
a581be46cf140e810c9bd68acba4835b5e060725f7d571cd1fe5dc1a9b3e434e
BLAKE2b-256 checksum
How to use checksums
75ade6e71532288363ed19ac7e267ac90290179ced080c1854e5791ac0165178
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / bluesky_nats-2.0.0-py3-none-any.whl

Download URL bluesky_nats-2.0.0-py3-none-any.whl
Size 38.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
be4313fb8c7ef74eec9b70ccb5100f1b4d499754d24ca8d6113b00ba80d4456e
BLAKE2b-256 checksum
How to use checksums
a2ed8d6bdd43dda6156884d5473cbd06f3789afe9eff098fb646dd401c9d6648
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Security for bluesky-nats 2.0.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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