Azure Function遇到System.Net.Sockets.SocketException

时间:2019-09-20 13:17:39

标签: c# asp.net-core azure-functions tcpclient socketexception

我有带有2个HTTP触发函数的AzureFunctions应用程序。两者都从同一个类中删除,但是使用不同的url来获取数据。 每天Azure Data Factory管道都会触发第一个HTTP功能 而另一个管道在1分钟内调用了第二个功能

每个功能向第三方网站发出大约1300个HTTP请求,并将每个响应作为单独的json文件存储在Blob存储中。

问题几乎是每次(但并非总是)第二个函数引发System.Net.Sockets.SocketException,因为很少有出站请求遇到常见的21秒TCP超时。 我注意到的一件奇怪的事情-出于某种原因,我的出站请求可能会受到Azure限制:第一批耗时接近300ms,下一个序列耗时4.3秒,然后9.5秒,下一个批次达到21秒,例外

Here is image of timing increasing of outbound requests

异常堆栈跟踪:

  

System.Net.Http.HttpRequestException:连接尝试失败   因为关联方在一段时间后未正确响应   时间或建立的连接失败,因为连接的主机具有   无法响应---> System.Net.Sockets.SocketException:A   连接尝试失败,因为连接方未正确   一段时间后响应,或建立的连接失败   因为连接的主机无法响应   System.Net.Http.ConnectHelper.ConnectAsync(字符串主机,Int32端口,   CancellationToken cancellingToken)-内部异常结束   堆栈跟踪---   System.Net.Http.ConnectHelper.ConnectAsync(字符串主机,Int32端口,   的CancellationToken cancelToken()   System.Threading.Tasks.ValueTask 1.get_Result() at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Threading.Tasks.ValueTask 1.get_Result()位于   System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask 1 creationTask) at System.Threading.Tasks.ValueTask 1.get_Result()
  在   System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage   request,布尔值doRequestAuth,CancellationToken cancelledToken)
  在System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage   的请求,在   System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage   的请求,在   System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask,   HttpRequestMessage请求,CancellationTokenSource cts,布尔值   disposeCts)   FunctionApp.BaseFunc。<> c__DisplayClass7_2。 d.MoveNext()   在   E:\ vsts-agent-win-1_work \ 339 \ s \ Services \ Host \ Controllers \ BaseFunc.cs:line   102   ---从上一个引发异常的位置开始的堆栈跟踪---在FunctionApp.BaseFunc.ProcessRun(ILogger   log,String runId)在   E:\ vsts-agent-win-1_work \ 339 \ s \ Services \ Host \ Controllers \ BaseFunc.cs:line   122。

FunctionApp托管在AppService计划S1上,因此没有600的出站连接限制(我相信是这样)

异常期间TCP连接的度量(最大值为498): Metrics of AzureFunction App

AzureFunction App的“解决问题”助手的TCP连接 Max TCP connections in all states was 502

异常期间的CPU和应用程序内存服务计划: App Service Plan metrics

应用程序是.Net Core 2.2

我没有设法在本地PC上重现此内容。但是在Azure上,几乎每天都会在每种环境(开发,测试,生产)上发生这种情况。 失败之后,Azure数据工厂将在5分钟内重试,并且每次都会成功。

这是两个函数都使用的基类代码:

 public abstract class BaseFunc
{
    protected abstract string BlobFolderName { get; }
    protected TelemetryClient telemetryClient;
    private static HttpClient _httpClient;

    static BaseFunc()
    {
        HttpClientHandler handler = new HttpClientHandler();
        handler.MaxConnectionsPerServer = 300;
        _httpClient = new HttpClient(handler);
    }
    protected async Task ProcessRun(ILogger log, string runId)
    {
        int processedItems = 0;
        try
        {
            Stopwatch sw = Stopwatch.StartNew();
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            await Authentication("url", log, runId); //sets default Authorization header

            string getIdeaResult = await _httpClient.GetStringAsync("url");
            JObject jsonObject = JObject.Parse(getIdeaResult);
            int ideaCount = (int)jsonObject.SelectToken("total_count");

            List<Task> tasks = new List<Task>();
            string DataPulledDate = DateTime.Now.ToString("dd-MMM-yyyy");
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse("connection string");
            CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("container");

            string getIdsUri = "url" + $"&limit={batchSize}&offset=";
            int iterations = (int)Math.Ceiling((decimal)ideaCount/batchSize);

            for (int i = 0; i < iterations; i++)
            {
                string result = await _httpClient.GetStringAsync("url" + i * 50);
                JObject jsonIdsObject = JObject.Parse(result);
                int[] ideaIds = jsonIdsObject["content"].Children().Values<int>("id").ToArray();
                foreach (int id in ideaIds)
                {
                    tasks.Add(Task.Run(async () =>
                    {
                        string content = null;
                        using (var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "url"+ id))) //Exception is thrown on this line
                        {
                            content = await response.Content.ReadAsStringAsync();
                            response.EnsureSuccessStatusCode();
                        }
                        CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference($"{DataPulledDate}/{BlobFolderName}/ideaId-{id}.json");
                        await cloudBlobContainer.CreateIfNotExistsAsync();
                        await cloudBlockBlob.UploadTextAsync(content);
                        Interlocked.Increment(ref processedItems);
                    }));
                }
            }
            await Task.WhenAll(tasks);
            sw.Stop();
        }
        catch (Exception ex)
        {
            log.LogError(ex, "{RunId}: Run failed. {Items} items processed successfully, Exception: {Exception}.", runId, processedItems, ex.ToString());
            throw;
        }
        finally
        {
            if (telemetryClient != null)
            {
                telemetryClient.Flush();
                Thread.Sleep(3000);
            }
        }
    }
}

功能代码本身:

namespace FunctionApp
{
    public class GetIdeas : BaseFunc
    {
        public GetIdeas(TelemetryClient telemetryClient)
        {
            this.telemetryClient = telemetryClient;
        }

        protected override string BlobFolderName { get => "folder"; }
        protected override string GetItemUrl { get => "url"; }

        [FunctionName("GetIdeasFn")]
        public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
        {
            await ProcessRun(log, $"GetIdeasFn - {DateTime.UtcNow.Ticks}");
        }
    }
}

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

我也遇到了同样的问题,但就我而言,我有一个代码补丁,其中包含一个无限的while循环,该循环正在创建数百个对Microsoft GraphApi的请求,而没有响应一个请求,它正在创建另一个请求。我更正了,问题解决了!也许对某人有帮助