Azure function speed is extremely slow and inconsistent

I am writing several Azure script functions that read and write from / to an internal database and display relevant information on a web page.

I noticed extreme slowness or even a timeout in the web interface when loading a web page that calls the Azure Function script. After further research, I realized that the following:

  • Azure function scripts sometimes take from 10 seconds to more than 1 minute to connect to an SQL database.
  • Sometimes scripts will run in a few milliseconds, and it will take more than 3 minutes to fully run the script.

Here is my Azure Function script:

module.exports = function(context, req) { context.log("Function Started: " + new Date()); // Import package const sql = require('mssql'); var _ = require('underscore-node'); var moment = require('moment'); var Promise = require('promise'); // Create a configuration object for our Azure SQL connection parameters var config = { server: "***", // Use your SQL server name database: "***", // Database to connect to user: "***", // Use your username password: "***", // Use your password port: ***, // Since we're on Windows Azure, we need to set the following options options: { encrypt: true }, multipleStatements: true, parseJSON: true }; var flagDefinitionId = null; if (req.query.Id == null || req.query.Id == "" || req.query.Id.length == 0) { context.res = { // status: 200, /* Defaults to 200 */ body: "No have flagDefinitionId " }; context.done(); // return; } var listTicketsFlag = []; flagDefinitionId = req.query.Id; sql.close(); var DBSchema = "b8akjsms2_st."; sql.connect(config).then(function() { context.log("SQL Connected: " + new Date()); var getAllEventTicketGoToMarket = new Promise(function(resolve, reject) { var queryGetEvent = ";WITH EventLog1 AS(" + " SELECT MD1, max([DateTime]) as LTime from " + DBSchema + "EventLog" + " where ([Event] = 'Ticket_Go_To_Market' OR [Event] = 'Acknowledge_Timeout')" + " group by MD1 )" + " SELECT * from ( SELECT EV.MD1 , EV.MD2," + " (SELECT COUNT(*) from " + DBSchema + "EventLog where MD1 = EV.MD1 and [Event] = 'Market_Ticket_Clear') as TotalClear" + " FROM " + DBSchema + "[Ticket] T" + " JOIN (SELECT E.* from " + DBSchema + "EventLog E join EventLog1 E1 on E.MD1 = E1.MD1 and E.[DateTime] = E1.LTime) EV ON T.Id = EV.MD1" + " WHERE T.IsInMarket = 1 and EV.MD2 <> ''" + " AND T.Id NOT IN (Select TicketId from " + DBSchema + "TicketFlag where FlagDefinitionId = " + flagDefinitionId + ")" + " ) R where R.TotalClear > 0"; context.log("get event log - Ticket_Go_To_Market" + queryGetEvent); new sql.Request().query(queryGetEvent, (err, result) => { context.log("this is --------> EventLog " + result.recordset.length); resolve(result.recordset); }); }); Promise.all([getAllEventTicketGoToMarket]).then(function(values) { var ticketGoToMarket = values[0]; context.log("this is --------> values: " + values[0].length + " ==+++++==== " + JSON.stringify(values[0], null, 2)); if (ticketGoToMarket.length != 0) { listTicketsFlag = _.filter(ticketGoToMarket, function(num) { var countSP = num.MD2.split(','); // context.log("countSP =====> " + countSP.length + "num.TotalClear ==>" + num.TotalClear) if (num.TotalClear > countSP.length) { return num.MD1; } }); // context.log("listTicketsFlag =====> " + JSON.stringify(listTicketsFlag, null, 2)); } insertTicketFlag(); }); function insertTicketFlag() { context.log("this is ----- ===> Insert: " + listTicketsFlag); // insert var insertTicketFlagPromise = new Promise(function(resolve, reject) { context.log("listTicketFlag ----- ===> " + listTicketsFlag.length); if (listTicketsFlag.length == 0) { context.log(" -------------------- No have ticket need FLAG"); resolve(); } else { // insert new data to TicketFlag FlagTickets var listTicketInsert = ""; //convertArrayToSQLString(listTicketsFlag, true, flagDefinitionId); var len = listTicketsFlag.length - 1; for (var j = 0; j <= len; j++) { listTicketInsert += '(\'' + listTicketsFlag[j] + '\', \'' + flagDefinitionId + '\')'; if (j != len) { listTicketInsert += ","; } } context.log("HERE : " + listTicketInsert); var insertQuery = 'Insert into ' + DBSchema + '[TicketFlag] (TicketId, FlagDefinitionId) values ' + listTicketInsert + ''; context.log("this is --------> InsertQuery" + insertQuery); // return; context.log("read data of FlagRule"); new sql.Request().query(insertQuery, (err, result) => { context.log("this is --------> insertQuery"); resolve(result); }); } }); Promise.all([insertTicketFlagPromise]).then(function(values) { context.log("DONE ALL"); sql.close(); context.done(); }) } }).catch(function(err) { console.log(err); context.done(); }); 

};

enter image description here

enter image description here

How to solve this problem of slowness?

+5
source share
1 answer

We noticed this with our node.js functions. After much research and testing, we found here:

  • Function services go cold after five minutes of inactivity. When they get out of a cold state, you can expect up to 10 seconds of what appears to be a compilation / transpilation of node JavaScript into .Net code so that they can run from within a larger functional engine. Please note that I said “Functional Application” above, and not just “Function”

  • Even if it is in a “hot” state (i.e. for 5 minutes of inactivity), there are times when a function loads external libraries for a longer time

  • The biggest culprit for this success is the large external library with many small files.

So what can you do to facilitate this? Here's what we did in order of complexity:

  • Timer Setting Function performed in less than 5 minutes. We start a simple timer every four minutes, which takes from 0 ms to 10 ms, and you can do the math to see what a VERY cheap way to keep your app-application hot.

  • Use the Functions-Pack to merge all your external libraries into one file. When a function is recompiled or crowded, or whatever magic happens there, it becomes much faster since it does not need to search for tens or hundreds of files.

  • Using the REST API instead of the SDK means that zero external libraries are needed. The big problem is creating authorization headers, there is no standard for Azure to create an Auth header, and this part of their documents is almost not covered in most cases, especially with node.js. I was thinking of running the github repository exclusively for node.js code that generates various Azure Auth tokens.

  • Port your functions to C # (yes, I'm not happy with this option - I need the JavaScript / TypeScript platform for our product). However, remove cross-compilation / transpilation / whatever, and it should speed up. I am porting one of our most complex functions in C # to further test this theory.

  • Switching to an application maintenance plan seems contrary to the value of Azure features. I want the unlimited scale that Microsoft handles, and the cost per run. The App Service plan makes me think again about CPU and memory and App Capacity.

Here is the MSDN forum forum that I posted asking for answers to our questions.

+4
source

Source: https://habr.com/ru/post/1269424/


All Articles