跳到主要内容

进阶:客户端结果与取消

客户端结果

服务器可以调用单个客户端的方法并等待其返回值。客户端必须为该方法注册 处理器;处理器返回的非 None 值作为结果回发。

class EchoHub(Hub):
async def ping_client(self) -> str:
return await self.clients.caller.invoke("client_method", "hello-from-server")

客户端侧:

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

connection.on("client_method", client_method)

result = await connection.invoke("ping_client")
print(result) # "ack:hello-from-server"
  • invoke(method, *args) 返回客户端结果;客户端返回错误时抛 HubException
  • 可选 timeout 参数:客户端未在时限内应答时抛 SignalRError
  • 客户端结果按连接用服务器生成的调用 id(s1s2 …)跟踪。

工作原理

  1. 服务器为新的调用 id 注册一个 future。
  2. 向客户端发送带该调用 idInvocation 消息。
  3. 客户端运行处理器,回复携带返回值(或错误)的 Completion
  4. 服务器解析 future。

取消

客户端可以用 CancelInvocation 取消在途调用。服务器以两种方式响应:

  • 置位该调用的 cancellation_token(一个 asyncio.Event)。
  • 取消运行 hub 方法的底层任务。
class ProbeHub(Hub):
async def cancelable(self, n: int, cancellation_token: Any = None) -> int:
try:
for i in range(n):
await asyncio.sleep(0.05)
if cancellation_token is not None and cancellation_token.is_set():
return i
return n
except asyncio.CancelledError:
return -1

aiosignalr 客户端在 stream() 迭代器被提前放弃时自动发送 CancelInvocation

并行调用

默认每条连接一次处理一个调用(maximum_parallel_invocations = 1),与参考 服务器一致。调高可让单条连接并发运行多个 hub 方法:

server = SignalRServer(MyHub, options=ServerOptions(maximum_parallel_invocations=4))

流式方法始终在独立任务上启动,因此流式期间不会占用调用信号量。