You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure SignalR Service无法收发消息问题排查求助

Azure SignalR 消息收发故障排查

我编写了一套SignalR演示代码,计划在机器A上向Azure SignalR Service发送消息,机器B接收消息。测试时无报错信息,但机器B无法收到任何消息。查看SignalR控制台图表,连接数据显示正常,但消息计数图表无数据。

相关代码

SignalR客户端核心代码

import datetime
import time
import base64
import hmac
import hashlib
import jwt,os
from configs.init_env import init_env
from logging.handlers import RotatingFileHandler
from signalrcore.hub_connection_builder import HubConnectionBuilder

class SignalRClient():
    def __init__(self, submission_id):
        init_env()
        self.connection_string = os.getenv("AZURE_SIGNALR_CONNECTION_STRING")
        if not self.connection_string:
            raise ValueError("AZURE_SIGNALR_CONNECTION_STRING environment variable is not set or is empty.")
        # Parse connection string
        parts = dict(s.split('=', 1) for s in self.connection_string.split(';') if s)
        self.endpoint = parts.get("Endpoint")
        self.access_key = parts.get("AccessKey")
        self.submission_id = submission_id

        if isinstance(self.submission_id, int):
            self.submission_id = str(self.submission_id)
        else:
            self.submission_id = str(self.submission_id)
            self.submission_id = self.submission_id[:4]
        self.hub_name = f"loghub{self.submission_id}"
        audience_url = f"{self.endpoint}/client/?hub={self.hub_name}"
        try:
            self.hub_connection = HubConnectionBuilder() \
                .with_url(audience_url, options={
                    "access_token_factory": self.generate_access_token
                }) \
                .build()
            self.hub_connection.start()
        except Exception as e:
            raise Exception(f'Failed to connect to SignalR: {e}')

    def generate_access_token(self):
        """Generate JWT token for Azure SignalR."""
        payload = {
            "aud": f"{self.endpoint}/client/?hub={self.hub_name}",
            "exp": int(time.time()) + 3600,  # Token expiration time (1 hour)
            "iat": int(time.time())
        }

        token = jwt.encode(payload, self.access_key, algorithm="HS256")
        return token

    def emit(self, message_type, message):
        try:
            res = self.hub_connection.send(message_type, [message])
            return res
        except Exception as e:
            raise Exception(f"Failed to send message to SignalR: {e}")

    def listen(self):
        """Listen for messages from Azure SignalR and print them."""
        print("Listening for messages...")

        def on_message(message):
            print(f"Received message: {message}")

        self.hub_connection.on("ReceiveMessage", on_message)

机器A发送消息测试代码

import unittest
from autotest.signalr.signalr import SignalRClient
import threading
import time

class TestSignalr(unittest.TestCase):

    def setUp(self):
        self.signalr_client = SignalRClient(100)

    def test_listen_messages(self):
        loop = 0
        while loop < 30000:
            time.sleep(1)
            res = self.signalr_client.emit("Emit_Log", f"Message {loop}")
            invocation_id = res.invocation_id
            print(f"Sent message {loop} with invocation id: {invocation_id}")
            loop += 1

if __name__ == '__main__':
      unittest.main()

机器B接收消息测试代码

import unittest
from autotest.signalr.signalr import SignalRClient
import threading
import time

class TestSignalr(unittest.TestCase):
    def setUp(self):
        self.signalr_client = SignalRClient(100)
    def test_listen_messages(self):
        self.signalr_client.listen()
        loop = 0
        while loop < 30000:
            time.sleep(3)
            print("Main thread is still running...")
            loop += 1

if __name__ == '__main__':
      unittest.main()

问题根源与修复方案

1. 消息收发方法名不匹配

机器A调用emit("Emit_Log", ...)发送消息,但机器B监听的是ReceiveMessage方法,两者名称完全不匹配,Azure SignalR无法将消息路由到正确的监听逻辑。
修复:统一两端的方法名,比如都用ReceiveLog:

  • 机器A发送改为:self.signalr_client.emit("ReceiveLog", f"Message {loop}")
  • 机器B监听改为:self.hub_connection.on("ReceiveLog", on_message)

2. 缺少消息中转逻辑

Azure SignalR Service是中继服务,并非直接的P2P消息通道。直接通过客户端发送消息时,需要有后端服务(或无服务器函数)负责消息的转发广播。当前代码没有实现这一层中转,导致消息无法从机器A传递到机器B。
可选修复方案:

方案一:使用Azure Functions无服务器中转(推荐)

创建Azure Function并绑定SignalR,编写转发逻辑:

import azure.functions as func

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)

@app.route(route="negotiate")
@app.signal_r_negotiate(connection_string_setting="AzureSignalRConnectionString")
def negotiate(req: func.HttpRequest) -> func.HttpResponse:
    return func.SignalRNegotiateResponse()

@app.signal_r_trigger(arg_name="req", hub_name="loghub100", event="ReceiveLog")
def signalr_trigger(req: func.SignalRInvocationContext) -> func.SignalRMessage:
    # 广播消息给所有连接的客户端
    return func.SignalRMessage(
        target="ReceiveLog",
        arguments=[req.arguments[0]]
    )

客户端需修改连接逻辑,通过Function的negotiate接口获取连接信息,而非直接连接Azure SignalR的endpoint。

方案二:搭建后端Hub服务

编写ASP.NET Core SignalR Hub处理消息转发:

using Microsoft.AspNetCore.SignalR;

public class LogHub : Hub
{
    public async Task ReceiveLog(string message)
    {
        // 广播给所有在线客户端
        await Clients.All.SendAsync("ReceiveLog", message);
    }
}

配置后端服务与Azure SignalR集成后,客户端连接到后端Hub,由后端完成消息转发。

3. 补充连接状态监听

在SignalRClient的__init__方法中添加连接断开重连逻辑,确保连接稳定:

def on_closed():
    print("Connection closed, attempting to reconnect...")
    self.hub_connection.start()

self.hub_connection.on_close(on_closed)

4. 验证JWT Token有效性

打印生成的JWT Token,检查aud字段是否符合{endpoint}/client/?hub={hub_name}格式,确保权限验证通过。

内容的提问来源于stack exchange,提问作者Steven Guo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:42:12