Azure Function hangs on error - node.js

If you have a error in code and did not callback, Azure Function just hangs.
AWS by default detects for empty loop and exits the lambda and logs the error, return the call to the caller with 5xx. It can also be controlled with callbackWaitsForEmptyEventLoop = false.
Is there is anything in Azure Functions that we can control how the function should exist in case of unhandled exceptions.

This currently isn't supported on Azure Functions.
It's the first I've heard this request, but it's a good idea. If you open a GitHub issue for it, I can take a look. (I'm the dev responsible for Node.js on Azure Functions) https://github.com/Azure/azure-functions

If you are using Azure Functions beta instead of using callbacks you may also export your functions as async which should allow the node worker to handle the exception without further intervention.
When exporting async functions calling the callback is redundant, and unnecessary.
Example:
module.exports = async function (context, req) {
throw new Error('Error')
}
Returns:
Request URL:http://localhost:7071/api/HttpTriggerJS
Request Method:GET
Status Code:500 Internal Server Error
Remote Address:[::1]:7071
Referrer Policy:no-referrer-when-downgrade

Related

Async function in NodeJS EventEmitter on AWS Lambda

I have an AWS Lambda application built upon an external library that contains an EventEmitter. On a certain event, I need to make a HTTP request. So I was using this code (simplified):
myEmitter.on("myEvent", async() => {
setup();
await doRequest();
finishingWork();
});
What I understand that happens is this:
My handler is called, but as soon as the doRequest function is called, a Promise is returned and the EventEmitter continues with the next handlers. When all that is done, the work of the handler can continue (finishingWork).
This works locally, because my NodeJS process keeps running and any remaining events on the eventloop are handled. The strange thing is that this doesn't seem to work on AWS Lambda. Even if context.callbackWaitsForEmptyEventLoop is set to true.
In my logging I can see my handler enters the doRequest function, but nothing after I call the library to make the HTTP call (request-promise which uses request). And the code doesn't continue when I make another request (which I would expect if callbackWaitsForEmptyEventLoop is set to false, which it isn't).
Has anyone experienced something similar and know how to perform an ansynchronous HTTP request in the handler of a NodeJS event emitter, on AWS Lambda?
I have similar issue as well, my event emitter logs all events normally until running into async function. It works fine in ECS but not in Lambda, as event emitter runs synchronously but Lambda will exit once the response is returned.
At last, I used await-event-emitter to solve the problem.
await emitter.emit('onUpdate', ...);
If you know how to solve this, feel free to add another answer. But for now, the "solution" for us was to put the eventhandler code elsewhere in our codebase. This way, it is executed asynchronously.
We were able to do that because there is only one place where the event is emitted, but the eventhandler way would have been a cleaner solution. Unfortunately, it doesn't seem like it's possible.

Error "ReferenceError: request is not defined" from basic Firebase Functions run

Trying to send off a webhook to Slack whenever onWrite() is triggered directed toward my Firebase DB. Going off a few other posts/guides I was able to deploy the below code, but get the ReferenceError: Request is not defined error on execution. I can't figure out how to fix the Request is not defined.
const functions = require('firebase-functions');
const webhookURL = "https://hooks.slack.com/services/string/string";
exports.firstTest = functions.database.ref('first').onWrite( event => {
return request.post(
webhookURL,
{json: {text: "Hello"}}
);
});
Calling your Cloud Function via an URL and sending back a response
By doing exports.firstTest = functions.database.ref('first').onWrite() you trigger your firstTest Cloud Function when data is created, updated, or deleted in the Realtime Database. It is called a background trigger, see https://firebase.google.com/docs/functions/database-events?authuser=0
With this trigger, everything happens in the back-end and you do not have access to a Request (or a Response) object. The Cloud Function doesn't have any notion of a front-end: for example it can be triggered by another back-end process that writes to the database. If you want to detect, in your front-end, the result of the Cloud Function (for example the creation of a new node) you would have to set a listener to listen to this new node location.
If you want to call your function through an HTTP request (possibly from your front-end, or from another "API consumer") and receive a response to the HTTP Request, you need to use another type of Cloud Function, the HTTP Cloud Function, see https://firebase.google.com/docs/functions/http-events. See also the other type of Cloud Function that you can call directly: the Callable Cloud Functions.
Finally, note that:
With .onWrite( event => {}), you are using the old syntax, see https://firebase.google.com/docs/functions/beta-v1-diff?authuser=0
The Firebase video series on Cloud Function is a good point to start to learn more on all these concepts, see https://firebase.google.com/docs/functions/video-series?authuser=0
Calling, from your Cloud Function, an external URL
If you want, from a Cloud Function, to call an external URL (the Slack webhook mentioned in your question, for example) you need to use a library like request-promise (https://github.com/request/request-promise).
See How to fetch a URL with Google Cloud functions? request? or Google Cloud functions call URL hosted on Google App Engine for some examples
Important: Note that you need to be on the "Flame" or "Blaze" pricing plan.
As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse on the question mark situated after the "Cloud Functions" title)

AWS Lambda function times out when I require aws-sdk module

I'm trying to query a DynamoDB table from a Lambda function (for an Alexa skill), but when I send the intent that calls require('aws-sdk'), the skill seems to hang and timeout. The Alexa test page just says "There was a problem with the requested skill's response", and I don't see any errors in the CloudWatch logs. I have the skill set up to catch any errors and return them as a spoken response, so I'm sure it's not an uncaught exception. I've also tried wrapping the require in a try/catch block, but that didn't work either.
This is the module that gets loaded with require if the test database intent request is received:
const AWS = require('aws-sdk');
module.exports = () => {
return 'Success!';
};
If I comment out require('aws-sdk'), the function works properly and Alexa responds with "Success".
Why does my skill break when all I'm doing is requiring the aws-sdk module?
I'm very new to AWS and this is my first experience trying to access a DynamoDB table in a Lambda function.
The Lambda function is uploaded as a zip that contains my source code, package.json (that includes aws-sdk as a dependency), and the node_modules folder.
After hours of debugging, I've found that changing import * as AWS from 'aws-sdk'; to import {DynamoDB} from 'aws-sdk'; (or {CloudFront} or whatever you actually use) made the timeout issue disappear. Mind you, the time to actually connect to DynamoDB was never an issue for me, it was always the import line where the timeout happened.
This can be fixed by either increasing the timeout or the memory allotted to the lambda function.
This is probably because the SDK is too big to be imported by the default timeout value of 3 seconds and the default memory value of 128 MB.
This is why it will probably work if you try importing smaller components like only DynamoDB.
Lambda, when using NodeJS, uses a callback continuation model. Your module should export a function that takes three parameters: event, context, and callback.
Event provides input parameters.
The other two are used for returning control from your handler function, depending on the NodeJS version you are using.
Try adding the three parameters that I mentioned and the, from within your exported handler function, call:
module.export = function(event, context, callback) {
callback(‘success’);
}
Bear in mind, I wrote this on mobile off the top of my mind, so you may need to make small afjustments to the code but the idea is the same. Don’t return directly from the function, but call the callback to supply the response as a continuation. And note that in earlier versions of NodeJS, prior to version 4, you would have to use the context to set success or failure, rather than calling the callback.
For more details, see the Lambda with NodeJS tech docs on AWS.
The other thing to keep in mind is that for Alexa specifically, the response should be in the correct format. That is a JSON response that contains all the necessary elements as explained in the Alexa Skills Kit tech docs.
The Alexa ASK sdk that you’ve included generates those responses but I thought I should point you to the actual docs in case you were going to try building the response by hand to understand how it works.

How to have a Function App tell a Logic App that it failed

I have a Logic App invoking a Function App. The Function App may fail, and if it does, I want the Logic App to do it's retry thing. But I don't know what is the correct way of conveying failure back to the Logic App. My Function App signature is
public static async Task Run(...)
Is throwing an exception the only option? I assume there's a better way, as I want to Logic App to get back my out params even if the Function App fails.
The logic app calls your function app via webhook, so by throwing an exception you send an error http response back to logic apps.
You could, upon detecting an error in the function, create and return an error response yourself. Here's some documentation on logic app error handling, it might have info on the parameter handling you're hoping for: https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-exception-handling

Node domains on Azure Mobile Services

I can't seem to get domains to work on Azure Mobile Services (ZUMO). For example:
var myDomain = require('domain').create();
myDomain.on('error', function ()
{
console.log('got here');
});
myDomain.run(function() {
boo(); //throws
});
The on error handler of my domain will never get called. This exception will be caught by ZUMO and their 500 error will get returned. I'd prefer to trap the exception myself, log it, and return a 500 using my preferred JSON format. I realize that there is some global error trapping that ZUMO is doing but I would think that if I have a domain it should catch it before it bubbles up to the ZUMO wrapper. Any suggestions?
(ZUMO runs on Node 0.8.28)
The code you list will handle uncaught exceptions. Mobile Services scripts and the underlying async data operations are wrapped in try..catch blocks, so they will not invoke a domain error handler.
You should be handling errors in your scripts using normal error handling practices, i.e. try..catch blocks or error handling callbacks for promises. You can then return the appropriate response using res.send.

Resources