Azure Functions 消耗计划 WCF 客户端错误“尝试失败,因为已连接...”

Azure Functions Consumption Plan WCF Client Errors "attempt failed because the connected..."

提问人:Chris DaMour 提问时间:12/15/2020 最后编辑:Chris DaMour 更新时间:12/17/2020 访问量:478

问:

我们最近将基于 Azure Functions Durable Functions 的应用从专用的 s1/标准应用服务计划切换到动态 y1 计划,以达到相同的资金,现在我们收到一个常见错误:

“连接尝试失败,因为连接方在一段时间后未正确响应,或者建立的连接失败,因为连接的主机无法响应。”

这在应用程序运行大约一个小时后发生。异常来自 svcutil 生成的 wcf 客户端。我相当确定这与来自消费函数应用程序与“专用”应用程序计划的套接字连接限制有关,如 https://learn.microsoft.com/en-us/azure/azure-functions/functions-scale#service-limits 所述,但并不完全相信,因为我没有看到日志消息“超出主机阈值:连接”列在 https://learn.microsoft.com/en-us/azure/azure-functions/manage-connections#connection-limit

我们的客户端实际上是一个包装器,大约有十几个 WCF 客户端在我们的包装器构造上实例化。包装器将 DI 注册为单例

builder.Services.AddSingleton<IWrapperClient, OurSoapClient>();

public OurSoapClient(
            IMemoryCache memoryCache,
            IOptions<Options> options,
            ILogger<OurSoapClient> log
        )
        {
            this.options = options.Value;
            this.memoryCache = memoryCache;
            this.log = log;


            this.metaClient = new Meta.MetaWebServiceClient(
                Meta.MetaWebServiceClient.EndpointConfiguration.MetaWebServicePort,
                this.options.MetaHref
            );
            

            this.wmsClient = new Wms.WmsWebServiceClient(
                Wms.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsStageItemsClient = new Wms.Stage.Items.WmsWebServiceClient(
                Wms.Stage.Items.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsReceiptClient = new Wms.Stage.ExpectedReceipts.WmsWebServiceClient(
                Wms.Stage.ExpectedReceipts.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsStageRmaClient = new Wms.Stage.Rma.WmsWebServiceClient(
                Wms.Stage.Rma.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsStageShipmentsClient = new Wms.Stage.Shipments.WmsWebServiceClient(
                Wms.Stage.Shipments.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );


            this.wmsUpdateShipmentsClient = new Wms.Updates.ShippingResults.WmsWebServiceClient(
                Wms.Updates.ShippingResults.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsUpdatesReceivingResultsClient = new Wms.Updates.ReceivingResults.WmsWebServiceClient(
                Wms.Updates.ReceivingResults.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsUpdatesInventoryAdjustmentClient = new Wms.Updates.InventoryAdjustments.WmsWebServiceClient(
                Wms.Updates.InventoryAdjustments.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsInboundOrderClient = new Wms.Inbound.CurrentAndHistory.WmsWebServiceClient(
                Wms.Inbound.CurrentAndHistory.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsOutboundOrderClient = new Wms.Outbound.CurrentAndHistory.WmsWebServiceClient(
                Wms.Outbound.CurrentAndHistory.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsInboundOrderDetailsClient = new Wms.Inbound.CurrentAndHistoryDetails.WmsWebServiceClient(
                Wms.Inbound.CurrentAndHistoryDetails.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );

            this.wmsOutboundOrderDetailsClient = new Wms.Outbound.CurrentAndHistoryDetails.WmsWebServiceClient(
                Wms.Outbound.CurrentAndHistoryDetails.WmsWebServiceClient.EndpointConfiguration.WmsWebServicePort,
                this.options.WmsHref
            );
        }

切换回标准应用服务计划似乎使这种情况消失。 我相当确定持久函数不是这里的原因,但为了清楚起见,对客户端的所有调用都发生在 Orchestrator 或 Activity 函数......我们在两种函数类型中都看到了相同的失败错误。

我注意到重复的一个轶事是错误似乎发生在第二个 OurWrapperClient 实例化(再次实例化所有 wcf 客户端)之后......由于它是单一实例,因此这必须是 Azure Functions 控制平面启动我的应用的另一个实例

所以有几个问题:

  1. 知道如何证明这是与最大出站连接相关的问题吗?
  2. 关于这成为问题的原因的任何建议
  3. 假设这与 WCF 相关
    1. 使用 WCF 客户端的正确方法是什么,是否应该使用 USINGS 为每个调用实例化它们,或者是否可以像我们一样为每个包装器客户端实例化它们一次,然后只释放它们一次?
    2. 我们是否应该使用 DI 将它们实例化为单例,然后注入它们?这意味着我相信 DI 会调用 Dispose
    3. 有没有办法将要使用的HTTP客户端传递给WCF客户端生成的代码?许多Azure Functions最佳做法都说要为所有HTTP I/O使用单个注入的HTTP客户端,但我不明白如何使用WCF做到这一点。
wcf .net-core wcf-client azure-durable-functions

评论

0赞 Theobald Du 12/15/2020
这道题的错误和你一样,大家可以看看:stackoverflow.com/questions/17693353/...
0赞 Chris DaMour 12/15/2020
@TheobaldDu谢谢,但我的差异不是立竿见影的,只是在一段时间(~小时)后它才开始发生
0赞 Chris DaMour 12/16/2020
MS 支持票得出的结论是,我被分配的 Web 空间与我的目标存在通信问题,切换到其他 Web 空间似乎可以解决问题

答:

0赞 Chris DaMour 12/17/2020 #1

使用 app insights,我注意到大约需要一个小时的时间与我的应用在那个时间切换主机实例相对应。最终,我开始看到在部署时它会立即失败。IE有一个“坏”主机。打开了一个 MS 支持案例,他们远程进入了一个糟糕的状态,发现他们无法从该主机进行 TCP ping。

分配给您的每个网站空间都从IP池发出请求,我怀疑我的目标WAF出于某种原因阻止了其中一些IP。切换到保证新网站空间的新区域(它们在创建时分配,但特定于区域)使问题消失。

在此期间确实找到了 https://github.com/dotnet/runtime/issues/35508,看起来很相似