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.