Skip to main content

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 from Hub are 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 None marks the method as returning a result. Use -> None (or no annotation) for void methods.
  • Method names are lowered for lookup, so Add and add resolve to the same method.

Special parameters

Named parameters inject connection context and cancellation:

Parameter nameInjected value
context / hub_contextHubContext (see below)
cancellation_token / cancellationTokenasyncio.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
AttributeDescription
connection_idUnique id of the calling connection
headersHTTP headers of the first request
queryQuery string parameters of the first request
user_idUser 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.

  • HubException subclasses propagate their message verbatim.
  • Other exceptions are turned into a generic message unless ServerOptions.enable_detailed_errors is True:
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:

OptionDefaultDescription
keep_alive_interval15.0Server ping interval
client_timeout_interval30.0Timeout before a silent client is dropped
handshake_timeout15.0Handshake deadline
maximum_parallel_invocations1Max concurrent invocations per connection
maximum_receive_message_size32 KiBMax inbound frame size
stream_buffer_capacity10Per-upload-stream queue capacity
long_polling_timeout15.0Long Polling poll duration
enable_detailed_errorsFalseSend exception details to clients
allow_stateful_reconnectsFalseEnable stateful reconnect
stateful_reconnect_buffer_size100_000Outbound buffer byte limit
stateful_reconnect_timeout30.0Max time a dropped connection is kept

Next steps