Hub & Methods
Defining a hub
Subclass Hub and define public methods. Method names are
matched case-insensitively by the dispatcher.
from aiosignalr.server import Hub
class MathHub(Hub):
async def add(self, a: int, b: int) -> int:
return a + b
Method resolution rules
- Public methods only — names starting with
_and members inherited fromHubare ignored. - A method is a streaming method when it is an async generator
(
async def ... yield); otherwise it is a single-result method. Invoking a streaming method non-streamingly (or vice versa) returns an error. - The return type annotation decides whether the return value is sent back:
a return annotation other than
Nonemarks the method as returning a result. Use-> None(or no annotation) for void methods. - Method names are lowered for lookup, so
Addandaddresolve to the same method.
Special parameters
Named parameters inject connection context and cancellation:
| Parameter name | Injected value |
|---|---|
context / hub_context | HubContext (see below) |
cancellation_token / cancellationToken | asyncio.Event, set on cancel |
class ProbeHub(Hub):
async def slow(self, n: int, cancellation_token: Any = None) -> int:
for i in range(n):
await asyncio.sleep(0.05)
if cancellation_token is not None and cancellation_token.is_set():
return -1
return n
Hub context
self.context gives access to connection metadata:
class MyHub(Hub):
async def whoami(self) -> str:
return self.context.connection_id
async def headers(self) -> dict[str, str]:
return self.context.headers
| Attribute | Description |
|---|---|
connection_id | Unique id of the calling connection |
headers | HTTP headers of the first request |
query | Query string parameters of the first request |
user_id | User identifier (if set) |
Lifecycle hooks
on_connected and on_disconnected are called per connection:
class ChatHub(Hub):
async def on_connected(self) -> None:
await self.clients.all_.send("message", f"{self.context.connection_id} joined")
async def on_disconnected(self, exception) -> None:
print(f"{self.context.connection_id} left: {exception}")
on_connected is invoked once per logical connection (including across a
stateful reconnect).
Errors
If a hub method raises, the client receives a Completion with an error
message and the invocation raises HubException on the client.
HubExceptionsubclasses propagate their message verbatim.- Other exceptions are turned into a generic message unless
ServerOptions.enable_detailed_errorsisTrue:
server = SignalRServer(MyHub, options=ServerOptions(enable_detailed_errors=True))
Starting the server
server = SignalRServer(MyHub)
await server.serve("127.0.0.1", 8080, path="/hub")
Server options:
| Option | Default | Description |
|---|---|---|
keep_alive_interval | 15.0 | Server ping interval |
client_timeout_interval | 30.0 | Timeout before a silent client is dropped |
handshake_timeout | 15.0 | Handshake deadline |
maximum_parallel_invocations | 1 | Max concurrent invocations per connection |
maximum_receive_message_size | 32 KiB | Max inbound frame size |
stream_buffer_capacity | 10 | Per-upload-stream queue capacity |
long_polling_timeout | 15.0 | Long Polling poll duration |
enable_detailed_errors | False | Send exception details to clients |
allow_stateful_reconnects | False | Enable stateful reconnect |
stateful_reconnect_buffer_size | 100_000 | Outbound buffer byte limit |
stateful_reconnect_timeout | 30.0 | Max time a dropped connection is kept |