Timeout Azure Function if trigger other azure function - node.js

I am new Azure function. I want to call the Azure function which will trigger another Azure function. I have written bellow code but its giving me timeout. The code written in node js.
Please suggest what to do.
module.exports = async function (context, req, callback) {
UtilityAccountNumber=req.body.UtilityAccountNumber.split(',');
if(UtilityAccountNumber=='' || typeof UtilityAccountNumber==='undefined' || !(Array.isArray(UtilityAccountNumber) && UtilityAccountNumber.length) ){
response={
status: 0,
message:"Please provide utility acccount number."
};
else{
if(UtilityAccountNumber.length){
for(let accountNo of UtilityAccountNumber){
try
{
var options = {
host: process.env.API_HOST,
port: process.env.PORT,
path: '/api/'+process.env.WEBSCRAPERMASTER,
method: 'POST'
};
var myreq = http.request(options, function(res) {
});
myreq.end();
}
catch (ex) // if failed
{
await logHTTPErrorResponse(ex, huId);
console.error(ex);
}
}
}
}
context.res = {
status: 200,
body: response
};
};

Your code logic may be stuck at some point, so it gives you timeout.(Azure function has a default timeout limit.) I think the function chain of azure durable function fully meets your requirements, and you are using nodejs, so azure durable function is supported.
Please have a look of this:
https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-sequence?tabs=javascript

Related

how call a azure function from a html?

I need the following. Create an azure function that generates qr code. Until then I found a tutorial. HttpTrigger, in javascript, with node -qrcode library
But I need to call this function in a simple html/css I made. how to make?
The azure function looks like this:
//require the module qrcode
const QRCode = require('qrcode');
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if(req.query.text) {
let code;
try {
code = await QRCode.toDataURL(req.query.text);
} catch (err) {
context.log.error('ERROR', err);
throw err;
}
if (code) {
context.res = {
body: code
}
} else {
context.res = {
body: "Error: QR Code rendering error",
status: 400
}
}
} else {
context.res = {
body: "Error: Missing query string text",
status: 400
}
}
}
After you publish your function, you should get the Function URL from the Azure portal, and then make an HTTP call from inside your html page(for example using jQuery, ajax etc). In your function.json, you should have mentioned which HTTP methods your function supports , example GET, POST. Refer https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-node

How to connect to Azure SQL database from multiple Azure Functions TypeScript API endpoints

I'm creating an API in Azure Functions using TypeScript, with multiple endpoints connecting to the same Azure SQL Server. Each endpoint was set up using the Azure Functions extension for VS Code, with the HttpTrigger TypeScript template. Each endpoint will eventually make different calls to the database, collecting from, processing and storing data to different tables.
There don't seem to be any default bindings for Azure SQL (only Storage or Cosmos), and while tedious is used in some Microsoft documentation, it tends not to cover Azure Functions, which appears to be running asynchronously. What's more, other similar StackOverflow questions tend to be for standard JavaScript, and use module.exports = async function (context) syntax, rather than the const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> syntax used by the TypeScript HttpTrigger templates.
Here's what I've got so far in one of these endpoints, with sample code from the tedious documentation in the default Azure Functions HttpTrigger:
var Connection = require('tedious').Connection;
var config = {
server: process.env.AZURE_DB_SERVER,
options: {},
authentication: {
type: "default",
options: {
userName: process.env.AZURE_DB_USER,
password: process.env.AZURE_DB_PASSWORD,
}
}
};
import { AzureFunction, Context, HttpRequest } from "#azure/functions"
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
context.log('HTTP trigger function processed a request.');
const name = (req.query.name || (req.body && req.body.name));
if (name) {
var connection = new Connection(config);
connection.on('connect', function(err) {
if(err) {
console.log('Error: ', err)
}
context.log('Connected to database');
});
context.res = {
// status: 200, /* Defaults to 200 */
body: "Hello " + (req.query.name || req.body.name)
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
};
export default httpTrigger;
This ends up with the following message:
Warning: Unexpected call to 'log' on the context object after function
execution has completed. Please check for asynchronous calls that are
not awaited or calls to 'done' made before function execution
completes. Function name: HttpTrigger1. Invocation Id:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Learn more:
https://go.microsoft.com/fwlink/?linkid=2097909
Again, the async documentation linked to covers just the standard JavaScript module.exports = async function (context) syntax, rather than the syntax used by these TypeScript httpTriggers.
I've also been reading that best practice might be to have a single connection, rather than connecting anew each time these endpoints are called - but again unsure if this should be done in a separate function that all of the endpoints call. Any help would be much appreciated!
I'm glad that using the 'mssql' node package works for you:
const sql = require('mssql');
require('dotenv').config();
module.exports = async function (context, req) {
try {
await sql.connect(process.env.AZURE_SQL_CONNECTIONSTRING);
const result = await sql.query`select Id, Username from Users`;
context.res.status(200).send(result);
} catch (error) {
context.log('error occurred ', error);
context.res.status(500).send(error);
}
};
Ref:https://stackoverflow.com/questions/62233383/understanding-js-callbacks-w-azure-functions-tedious-sql
Hope this helps.

Simple Azure retrieveEntity is not executed at all

This very simple thing does not work for me even though I have practically copy + pasted the example code from here:
https://github.com/Azure/azure-storage-node
It seems that tableService.retrieveEntity never fires at all? The context.log does not print anything. I get a status 200 with no body but this is because that is Azure's default.
It is the same problem if I write a query and use the queryEntities-method as well.
I write these things in the Azure Portal for simplicity's sake.
This is my code:
var azure = require('azure-storage');
module.exports = async function (context, req) {
var tableService = azure.createTableService('myTable', 'GoYVMvN+SXRJhzVERIYWFu6k0/DkZINIerS+YpwmQVy3ppPFJ+8bTavfisHJvsNbo5hjgpw40bWv8XXXXXXXXX==');
tableService.retrieveEntity('myList', 'MyPartitionKey', '1', function(error, result, response) {
context.log("retrieving...")
if(!error){
context.res = {
status: 200,
body: "The entity was retrieved"
}
} else {
context.res = {
status: 500,
body: "The entity was not retrieved"
}
}
});
};

AWS Lambda publishing to IOT Topic fires indefinitely

The Issue:
I have a node.js (8.10) AWS Lambda function that takes a json object and publishes it to an IOT topic. The function successfully publishes to the topic, however, once fired it is continuously called until I throttle the concurrency to zero to halt any further calling of the function.
I'm trying to figure out what I've implemented incorrectly that causes more than one instance the of the function to be called.
The Function:
Here is my function:
var AWS = require('aws-sdk');
exports.handler = function (event, context) {
var iotdata = new AWS.IotData({endpoint: 'xxxxxxxxxx.iot.us-east-1.amazonaws.com'});
var params = {
topic: '/PiDevTest/SyncDevice',
payload: JSON.stringify(event),
qos: 0
};
iotdata.publish(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log("Message sent.");
context.succeed();
}
});
};
My test json is:
{
"success": 1,
"TccvID": "TestID01"
}
The test console has a response of "null", but the IOT topic shows the data from the test json, published to the topic about once per second.
What I've Tried
-I've attempted to define the handler in it's own, non-anonymous function called handler, and then having the exports.handler = handler; This didn't produce any errors, but didn't successfully post to the iot topic either.
-I thought maybe the issues was with the node.js callback. I've tried implementing it and leaving it out (Current iteration above), but neither way seemed to make a difference. I had read somewhere that the function will retry if it errors, but I believe that only happens three times so it wouldn't explain the indefinite calling of the function.
-I've also tried calling the function from another lambda to make sure that the issue wasn't the aws test tool. This produced the same behavior, though.
Summary:
What am I doing incorrectly that causes this function to publish the json data indefinitely to the iot topic?
Thanks in advance for your time and expertise.
Use aws-iot-device-sdk to create a MQTT client and use it's messageHandler and publish method to publish your messages to IOT topic. Sample MQTT client code is below,
import * as DeviceSdk from 'aws-iot-device-sdk';
import * as AWS from 'aws-sdk';
let instance: any = null;
export default class IoTClient {
client: any;
/**
* Constructor
*
* #params {boolean} createNewClient - Whether or not to use existing client instance
*/
constructor(createNewClient = false, options = {}) {
}
async init(createNewClient, options) {
if (createNewClient && instance) {
instance.disconnect();
instance = null;
}
if (instance) {
return instance;
}
instance = this;
this.initClient(options);
this.attachDebugHandlers();
}
/**
* Instantiate AWS IoT device object
* Note that the credentials must be initialized with empty strings;
* When we successfully authenticate to the Cognito Identity Pool,
* the credentials will be dynamically updated.
*
* #params {Object} options - Options to pass to DeviceSdk
*/
initClient(options) {
const clientId = getUniqueId();
this.client = DeviceSdk.device({
region: options.region || getConfig('iotRegion'),
// AWS IoT Host endpoint
host: options.host || getConfig('iotHost'),
// clientId created earlier
clientId: options.clientId || clientId,
// Connect via secure WebSocket
protocol: options.protocol || getConfig('iotProtocol'),
// Set the maximum reconnect time to 500ms; this is a browser application
// so we don't want to leave the user waiting too long for reconnection after
// re-connecting to the network/re-opening their laptop/etc...
baseReconnectTimeMs: options.baseReconnectTimeMs || 500,
maximumReconnectTimeMs: options.maximumReconnectTimeMs || 1000,
// Enable console debugging information
debug: (typeof options.debug === 'undefined') ? true : options.debug,
// AWS access key ID, secret key and session token must be
// initialized with empty strings
accessKeyId: options.accessKeyId,
secretKey: options.secretKey,
sessionToken: options.sessionToken,
// Let redux handle subscriptions
autoResubscribe: (typeof options.debug === 'undefined') ? false : options.autoResubscribe,
});
}
disconnect() {
this.client.end();
}
attachDebugHandlers() {
this.client.on('reconnect', () => {
logger.info('reconnect');
});
this.client.on('offline', () => {
logger.info('offline');
});
this.client.on('error', (err) => {
logger.info('iot client error', err);
});
this.client.on('message', (topic, message) => {
logger.info('new message', topic, JSON.parse(message.toString()));
});
}
updateWebSocketCredentials(accessKeyId, secretAccessKey, sessionToken) {
this.client.updateWebSocketCredentials(accessKeyId, secretAccessKey, sessionToken);
}
attachMessageHandler(onNewMessageHandler) {
this.client.on('message', onNewMessageHandler);
}
attachConnectHandler(onConnectHandler) {
this.client.on('connect', (connack) => {
logger.info('connected', connack);
onConnectHandler(connack);
});
}
attachCloseHandler(onCloseHandler) {
this.client.on('close', (err) => {
logger.info('close', err);
onCloseHandler(err);
});
}
publish(topic, message) {
this.client.publish(topic, message);
}
subscribe(topic) {
this.client.subscribe(topic);
}
unsubscribe(topic) {
this.client.unsubscribe(topic);
logger.info('unsubscribed from topic', topic);
}
}
***getConfig() is to get environment variables from a yml file or else you can directly specify it here.
While he only posted it as an comment, MarkB pointed me in the correct direction.
The problem was the solution was related to another lambda who was listening to the same topic and invoking the lambda I was working on. This resulted in circular logic as the exit condition was never met. Fixing that code solved this issue.

Send response back to client after google compute engine api call in node js

I am trying to get the Kubernetes cluster details from google cloud using google cloud Kubernetes API for node js.
Below is the example i have found in google documentation.
var google = require('googleapis');
var container = google.container('v1');
authorize(function(authClient) {
var request = {
projectId: 'my-project-id',
zone: 'my-zone',
clusterId: 'my-cluster-id',
auth: authClient,
};
container.projects.zones.clusters.get(request, function(err, response){
if (err) {
console.error(err);
return;
}
// TODO: Change code below to process the `response` object and send the detail back to client.
console.log(JSON.stringify(response, null, 2));
});
});
function authorize(callback) {
google.auth.getApplicationDefault(function(err, authClient) {
if (err) {
console.error('authentication failed: ', err);
return;
}
if (authClient.createScopedRequired && authClient.createScopedRequired()) {
var scopes = ['https://www.googleapis.com/auth/cloud-platform'];
authClient = authClient.createScoped(scopes);
}
callback(authClient);
});
}
As the google get API is asynchronous function, how can I return the response from API back to client.
The question is what do you want to do with the data? It's not an issue of the API being asynchronous or not, this snippet of code should return in the console the same JSON you would get with this request:
GET https://container.googleapis.com/v1beta1/projects/[PROJECT ID]/locations/[ZONE]/clusters/[CLUSTER NAME]
The function and callback should take care of the fact that it's asynchronous.

Resources