2 years ago

#69078

test-img

Glorfindel

What can I do about Azure Function leaking memory via CancellationTokenSource?

I'm analyzing the memory usage of Azure Functions under load test. When I run the template function with an HTTP trigger:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace TestFunction
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string name = req.Query["name"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            string responseMessage = string.IsNullOrEmpty(name)
                ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
                : $"Hello, {name}. This HTTP triggered function executed successfully.";

            return new OkObjectResult(responseMessage);
        }
    }
}

and test it by firing 100,000 HTTP calls at it in 10 parallel threads, from another Visual Studio instance:

using Microsoft.Extensions.Logging;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;

namespace TestProject1
{
    public class Tests
    {
        [Test]
        public async Task TestQueryFunction()
        {
            var url = "http://localhost:7071/api/Function1"; // "http://localhost:7071/api/GetTaskLogs?subscription-key=471f69529605476990ab8c074de44f9a&oil-tenant-id=testsuite-acc&ExternalID=IVQ20";
            var tasks = new List<Task>();
            for (int i = 0; i < 10; i++)
            {
                var threadNumber = i;
                tasks.Add(Task.Run(async () => {
                    await Task.Delay(threadNumber * 100);
                    var stopwatch = new Stopwatch();
                    for (int j = 0; j < 10000; j++)
                    {
                        stopwatch.Restart();
                        var response = await httpClient.GetAsync(url);
                        Debug.WriteLine(threadNumber + ", " + j + ": " + stopwatch.ElapsedMilliseconds);
                    }
                }));
            }
            await Task.WhenAll(tasks);
        }

        private static readonly HttpClient httpClient = new HttpClient();
    }
}

the memory usage of the Function has increased from 74MB (after startup) to 214MB. According to the snapshot, a lot of memory is tied to CancellationTokenSource which I don't use, at least not explicitly:

enter image description here

How can I prevent this? I found a related GitHub issue CancellationTokenSource is not disposed in ServiceBusListener.ProcessMessageAsync and ServiceBusListener.ProcessSessionMessageAsync (possible memory leak) but that's for Service Bus triggers and that has been fixed.

I'm using Visual Studio 2022, .NET Core 6 and Functions SDK 4.0.1, but I was also able to reproduce it in VS2019, .NET Core 3.1 and Functions SDK 3.0.13.

c#

memory-leaks

azure-functions

cancellationtokensource

0 Answers

Your Answer

Accepted video resources