【问题标题】:Azure SignalR InvokeAsync hangs when attempting to establish Group connection尝试建立组连接时 Azure SignalR InvokeAsync 挂起
【发布时间】:2021-04-22 22:09:08
【问题描述】:

在连接上调用 InvokeAsync 挂起。

我正在引用以下 document 在 Azure SignalR 中配置组连接。

注意:

我只能在不依赖组配置时建立连接。

客户:

var negotiateJson = await _client.GetStringAsync($"{host}{"negotiatefn"}");
var negotiate     = JsonConvert.DeserializeObject<NegotiateInfo>(negotiateJson);

var connection = new HubConnectionBuilder()
    .AddNewtonsoftJsonProtocol()
    .WithUrl(negotiate.Url, options => options.AccessTokenProvider = async () => negotiate.AccessToken)
    .Build();

connection.Closed -= Connection_Closed;
connection.Closed += Connection_Closed;

connection.On<JObject>(hubMethodName, OnCourierUpdate);

await connection.StartAsync();
await connection.InvokeAsync("JoinGroup", sessionId); // HANGS APP HERE !!!

服务器:Azure 函数

public static class LocationFn
{
    [FunctionName(nameof(LocationFn))]
    public static async Task<IActionResult> Run(
        [HttpTrigger(
            AuthorizationLevel.Anonymous,
            "post",
            Route = nameof(LocationFn))]
        HttpRequest req,
        [SignalR(HubName = "LocationHub")]
        IAsyncCollector<SignalRMessage> signalRMessages,
        ILogger log)
    {
        log.LogInformation($"{nameof(LocationFn)} has been invoked.");

        try
        {
            using (var streamReader = new StreamReader(req.Body))
            {
                var json = await streamReader.ReadToEndAsync();
                var subjectLocation = JsonConvert.DeserializeObject<SubjectLocation>(json);

                await signalRMessages.AddAsync(
                    new SignalRMessage
                    {
                        Target    = "LocationUpdate",
                        GroupName = subjectLocation.SessionId,
                        Arguments = new[] { subjectLocation }
                    });

                var message = Log(log, subjectLocation);

                return new OkObjectResult(message);
            }
        }
        catch (Exception ex)
        {
            return new BadRequestObjectResult("There was an error: " + ex.Message);
        }
    }
}



public static class JoinGroupFn
{
    [FunctionName(nameof(JoinGroupFn))]
    public static async Task<IActionResult> Run(
        [HttpTrigger(
            AuthorizationLevel.Anonymous,
            "post",
            Route = nameof(JoinGroupFn))]
        HttpRequest req,
        [SignalR(HubName = "LocationHub")]
        IAsyncCollector<SignalRMessage> signalRMessages,
        ILogger log)
    {
        log.LogInformation($"{nameof(JoinGroupFn)} has been invoked.");

        try
        {
            var groupId = await req.ReadAsStringAsync();

            await signalRMessages.AddAsync(
                new SignalRMessage
                {
                    Target    = "JoinGroup",
                    GroupName = groupId,
                    Arguments = new[] { groupId }
                });

            log.LogInformation($"{nameof(JoinGroupFn)} {groupId}");

            return new OkObjectResult(groupId);
        }
        catch (Exception ex)
        {
            return new BadRequestObjectResult("There was an error: " + ex.Message);
        }
    }
}

服务器:集线器

type LocationHub() as x =

    inherit Hub()

    let this = (x :> Hub)

    member x.LocationUpdate(v:SubjectLocation) =

        async { do! this.Clients.Group(v.SessionId).SendAsync("LocationUpdate", v) |> Async.AwaitTask

              } |> Async.StartAsTask

    member x.JoinGroup(groupId:string) =

        async { do! this.Groups.AddToGroupAsync(this.Context.ConnectionId, groupId) |> Async.AwaitTask

              } |> Async.StartAsTask

【问题讨论】:

  • 老实说,我唯一一次看到应用挂起是在服务器无法访问时。你确定网址正确吗?或者如果服务器是通过 https 托管的,那么 ssl 证书是有效的。
  • 我相信这个 URL 是正确的,因为我可以在没有组配置的情况下成功演示连接。
  • 这看起来有点混乱。您使用的是 Azure 函数还是使用 SignalR 库?看起来你在服务器端混合了两者?
  • @davidfowl 我都在使用。 stackoverflow.com/questions/67624175/…
  • 所以这个当前问题无效,新问题是使用无服务器集线器对吗?这是一个受支持的场景,这个问题以一种不受支持的方式将它们混合在一起。

标签: signalr azure-signalr


【解决方案1】:

我来自 Azure SignalR 团队,您的服务在 Serverless 模式下运行,它不允许任何服务器连接,您的 F# 集线器如何运行?

而在客户端,connection.InvokeAsync 需要服务器确认,由于服务器连接无法连接,因此无法从服务中获取任何确认。

如果您需要 hub 服务器,请将服务切换到 Default 模式,然后使用 Azure SignalR SDK 运行 hub,并验证服务器是否已连接(通过服务指标中的日志或连接计数)。

如果你想要 serverless,请移除 hub,你可以在 Functions 端添加一个 Serverless hub,参见:https://docs.microsoft.com/en-us/azure/azure-signalr/signalr-concept-serverless-development-config#class-based-model。 并且不要忘记设置上游,请参阅:https://docs.microsoft.com/en-us/azure/azure-signalr/concept-upstream#rule-settings

【讨论】:

  • 当没有组配置时,我可以在客户端和服务器之间建立连接。
  • 是的,你可以连接客户端,因为你使用函数来处理协商,它重定向到服务。但是,集线器不起作用。如果你在函数应用程序中编写集线器,该函数对集线器一无所知,它将被视为普通类,没有人使用它。如果您在另一个应用服务中编写集线器,并使用 Azure SignalR SDK,则服务器连接将被拒绝,因为您的服务处于无服务器模式。
  • 我认为您在服务中将上游留空,这将导致服务始终忽略来自客户端的所有消息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多