Skip to main content

aiosignalr

High-performance, asyncio-native implementation of the SignalR hub protocol for Python. Provides both a client and a server, covering the WebSocket, Server-Sent Events, Long Polling and HTTP Post transports with JSON and MessagePack message encoding.

Documentation

Full documentation (English & 简体中文) is available at:

https://truerou.github.io/aiosignalr/

The site source lives in website/ (Docusaurus) and is deployed to GitHub Pages by the deploy-docs workflow.

Features

  • Pure asyncio, no blocking calls.
  • Full-duplex client and server over WebSocket.
  • Transport fallback: the client negotiates transports in server-declared order (WebSocket → Server-Sent Events → Long Polling).
  • Both the JSON (json, 0x1E-delimited) and MessagePack (messagepack, VarInt length-prefixed) protocols.
  • Client: invoke, stream, send, client-to-server upload streams, server method handlers (on), keep-alive pings, server-timeout detection, automatic reconnect with a pluggable retry policy.
  • Server: hub methods (single result and streaming), groups, broadcast to all/connection/group/user, client results, cancellation, upload-stream parameters, negotiation and handshake protocol selection.
  • Server hosting: standalone asyncio server or an ASGI application mountable in uvicorn/FastAPI.
  • Stateful reconnect on both sides: useAck / Ack / Sequence message buffering that preserves in-flight invocations and broadcasts across a WebSocket drop, with exactly-once delivery (interoperates with the ASP.NET Core implementation).
  • Interop test-suite: aiosignalr ↔ real ASP.NET Core SignalR server, and a real ASP.NET Core SignalR client ↔ aiosignalr server (see tests/interop/).

Installation

uv add aiosignalr        # or: pip install aiosignalr

Requires Python 3.11+.

Client

import asyncio
from aiosignalr.client import HubConnection


async def main() -> None:
    connection = HubConnection()
    connection.on("message", lambda text: print("got:", text))

    await connection.start("ws://127.0.0.1:8080/hub")
    result = await connection.invoke("Add", 40, 2)
    print("Add(40, 2) =", result)

    async for item in await connection.stream("Counter", 3):
        print("stream item:", item)

    await connection.send("Notify", "hello")
    await connection.stop()


asyncio.run(main())

Server

import asyncio
from aiosignalr.server import Hub, ServerOptions, SignalRServer


class ChatHub(Hub):
    async def on_connected(self) -> None:
        await self.clients.all_.send("message", f"User {self.context.connection_id} joined")

    async def echo(self, text: str) -> str:
        return text

    async def counter(self, n: int):
        for i in range(n):
            yield i
            await asyncio.sleep(0.01)


async def main() -> None:
    server = SignalRServer(
        ChatHub,
        options=ServerOptions(allow_stateful_reconnects=True),
    )
    await server.serve("127.0.0.1", 8080, path="/hub")


asyncio.run(main())

To mount the server inside an existing ASGI application (uvicorn/FastAPI):

app = server.asgi_app()  # pass to uvicorn.run(app, ...)

Stateful reconnect

Both the client and the server implement the ASP.NET Core stateful-reconnect ("ack") protocol. When enabled, unacknowledged messages are buffered and replayed after a transport drop so in-flight invocations, streams and broadcasts survive without loss or duplication.

Client:

connection = HubConnection().with_stateful_reconnect()

Server:

SignalRServer(ChatHub, options=ServerOptions(allow_stateful_reconnects=True))

Stateful reconnect requires the WebSockets transport. The client sends a HubProtocol version-2 handshake and the negotiate response advertises useStatefulReconnect when the server agrees; the two sides then exchange Ack/Sequence messages and replay buffered messages across the reconnect.

Tests

uv run ruff format .
uv run ruff check .
uv run mypy src
uv run pytest                 # self-tests
uv run pytest tests/interop   # requires dotnet (real ASP.NET Core interop)

Documentation site

The docs site lives in website/ (Docusaurus, English + 简体中文) and is deployed automatically to GitHub Pages by .github/workflows/deploy-docs.yml on every push touching website/**.

Local development

cd website
npm install
npm start          # dev server at http://localhost:3000/aiosignalr/
npm run build      # static build into website/build/

One-time GitHub Pages setup

The workflow uses the official actions/deploy-pages action, which requires the Pages source to be GitHub Actions:

  1. Open Settings → Pages.
  2. Under Build and deployment → Source, select GitHub Actions.
  3. Push the workflow to main. The deploy job publishes https://truerou.github.io/aiosignalr/ (auto-enabled after the first run).

Adding a language

  • Write the docs under website/docs/ (English is the default locale).
  • Add the locale to website/docusaurus.config.jsi18n.locales.
  • Create website/i18n/<locale>/docusaurus-plugin-content-docs/current/ and mirror the file tree.
  • Run cd website && npm run write-translations -- --locale <locale> to scaffold the theme/code translations, then translate the JSON files.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aiosignalr-0.1.1.tar.gz (41.8 kB view details)

Uploaded Source

Built Distribution

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

aiosignalr-0.1.1-py3-none-any.whl (57.9 kB view details)

Uploaded Python 3

File details

Details for the file aiosignalr-0.1.1.tar.gz.

File metadata

  • Download URL: aiosignalr-0.1.1.tar.gz
  • Upload date:
  • Size: 41.8 kB
  • Tags: Source
  • Uploaded using 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":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for aiosignalr-0.1.1.tar.gz
Algorithm Hash digest
SHA256 0fccde5ff5198eb0a9f1a036b0670135e1a680944dfe9a6841620ab67a2e5048
MD5 37c5c92806946913c0c9d7970b7037e8
BLAKE2b-256 778f19ef04d43260aebd5f855608667801d5cf05932d347f29dedf38e7b58f16

See more details on using hashes here.

File details

Details for the file aiosignalr-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: aiosignalr-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 57.9 kB
  • Tags: Python 3
  • Uploaded using 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":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for aiosignalr-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 affcedf54c3612f53d634f8513aad672b4150ea2f8fb0c7c4e2850dcc02c25dc
MD5 1f86f7c8f8c3ae0f7ca429450104cad5
BLAKE2b-256 c04affb1defd3df0dd1afae900b20f5fed771d4db2b9833a805d62adb7248541

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 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