Melissa
Melissa

Reputation: 473

Same method in Azure Function takes longer

I was curious about how much the response times would be improved when moving an intensive method to an Azure Function. So I created 2 small applications. The first one is an ASP.NET MVC application (app service plan S1). The second one is an ASP.NET MVC application with 1 Azure Function (in a Function project), App Service plan S1 combined with a Consumption plan for the FunctionApp.

Both applications are the same except for 1 method, which is moved to an Azure Function, the MergeDocumentsAndExport. In my application a given number of Document records are created on application start.

public class Document {
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public byte[] Content { get; set; }
    public DateTime DateCreated { get; set; }
}

The enduser is able to download all the Documents in the database by clicking on a button in a view. When this button is clicked, the method MergeDocumentsAndExportis called.

Without Azure Functions

public byte[] MergeDocumentsAndExport()
{
    var startmoment = DateTime.Now;
    var baseDocument = new Spire.Doc.Document();
    var documents = _documentDataService.GetAllDocuments();

    foreach (var document in documents)
    {
        using (var memoryStream = new MemoryStream(document.Content))
        {
            var documentToLoad = new Spire.Doc.Document();
            documentToLoad.LoadFromStream(memoryStream, FileFormat.Doc);

            foreach (Section section in documentToLoad.Sections)
            {
                baseDocument.Sections.Add(section.Clone());
            }
        }
    }

    byte[] byteArrayToReturn;

    using (var memoryStream = new MemoryStream())
    {
        baseDocument.SaveToStream(memoryStream, FileFormat.Doc);
        byteArrayToReturn = memoryStream.ToArray();
    }

    _responseLogger.Log(startmoment, DateTime.Now, nameof(MergeDocumentsAndExport);
    return byteArrayToReturn;
}

The _responseLogger.Log(..) method logs the start and end of the method with the name of the method en determines the executiontime (maybe responselogger isn't the best name for this service).

With Azure Functions

The same method is transformed into an HTTP-triggered Azure Function.

[DependencyInjectionConfig(typeof(DependencyConfig))]
public static class MergeDocumentsAndExportFunction
{
    [FunctionName("MergeDocumentsAndExportFunction")]
    public static HttpResponseMessage Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", Route = "MergeDocumentsAndExport")]HttpRequestMessage req,
        TraceWriter log,
        [Inject]IDocumentDataService documentDataService,
        [Inject]IResponseLogger responseLogger)
    {
        var startmoment = DateTime.Now;
        log.Info("MergeDocumentsAndExportFunction processed a request.");

        var baseDocument = new Document();
        var documents = documentDataService.GetAllDocuments();

        foreach (var document in documents)
        {
            using (var memoryStream = new MemoryStream(document.Content))
            {
                var documentToLoad = new Document();
                documentToLoad.LoadFromStream(memoryStream, FileFormat.Doc);

                foreach (Section section in documentToLoad.Sections)
                {
                    baseDocument.Sections.Add(section.Clone());
                }
            }
        }

        using (var memoryStream = new MemoryStream())
        {
            baseDocument.SaveToStream(memoryStream, FileFormat.Doc);
            // Create response to send document as byte[] back.
            var response = req.CreateResponse(HttpStatusCode.OK);
            var buffer = memoryStream.ToArray();
            var contentLength = buffer.Length;
            response.Content = new StreamContent(new MemoryStream(buffer));
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/ms-word");
            response.Content.Headers.ContentLength = contentLength;

            responseLogger.Log(startmoment, DateTime.Now, "MergeDocumentsAndExport");
            return response;
        }
    }

In the MergeDocumentsAndExportFunction a bit of code is added like creating and returning a HttpResponseMessage. I didn't implement async calls, because it was only for this minor test and I wanted to compare the synchronous execution time of the method MergeDocumentsAndExport in both environments.

The results I got, was not what I was expecting. In almost every case the execution time was about the same or was much longer for the Azure Function. I know there is a startup time for an Azure Function and I excluded those. Maybe because the dependency injection with Autofac can take some time? The outcome in seconds when 1000 Documents from the database are merged and exported:

Without Azure Function:

With Azure Function:

The execution time of the same method in different environments can differ 30 seconds for merging 1000 documents into 1. How is it possible that the Azure Function takes longer to execute (+ 30 seconds)? Is it because I am using it wrong? Thanks.

Upvotes: 1

Views: 828

Answers (2)

Mikhail Shilkov
Mikhail Shilkov

Reputation: 35124

Azure Functions on Consumption Plan aren't very suitable to improve response time of long-running CPU-intensive workloads.

Based on my observation, the instances have quite moderate performance, so the request duration won't probably go down compared to fixed-plan App Service.

The strength of Functions is in short-lived executions with small- or variable throughput.

If you still want to compare, you could deploy the same Function App on Fixed App Service plan, measure the timings there and then choose what suits you best.

Upvotes: 2

Jarnstrom
Jarnstrom

Reputation: 477

If an Azure Function on consumption plan is idle it releases the reserved compute from the host. When a new request comes it takes some time for the function to start up and request new compute.

You can set a Function to use app service plan and "always on" setting instead of consumption plan and it should go faster. https://learn.microsoft.com/en-us/azure/azure-functions/functions-scale

Upvotes: 0

Related Questions