Skip to main content

Handling Server Calls

The server can call methods on the client in two ways: fire-and-forget notifications and client results (the server invokes a client method and waits for a return value).

Registering handlers

connection.on("target", handler)

When the server sends an Invocation (or StreamInvocation) for target, every registered handler is called with the message arguments:

connection.on("message", lambda text: print("got:", text))

Handlers can be async:

async def on_file(path: str, size: int) -> None:
await save_file(path, size)

connection.on("fileReady", on_file)

For a fire-and-forget server call (invocation_id is None), all handlers run and their return values are ignored.

Client results

When the server sends an invocation with an invocation id (client result), the handler's return value is sent back as the result:

async def client_method(text: str) -> str:
return f"ack:{text}"

connection.on("client_method", client_method)
  • If exactly one handler returns a non-None value, that value is sent as the result.
  • If no handler returns a value, an empty Completion is sent.
  • If a handler raises, the client sends a Completion with the error message.

The server side uses clients.caller.invoke("client_method", ...) to trigger this (see Client results).

Removing handlers

connection.remove("message", handler)

Unknown methods

If the server calls a method with no registered handler and an invocation id, the client replies with a Completion carrying "Unknown hub method '<target>'", which surfaces on the server as a HubException.

Ordering

Handlers are invoked in registration order. Fire-and-forget notifications are dispatched as background tasks so a slow handler does not block frame processing.