on event of firebase is not working with AWS lambda - node.js

In the following event .once event is working fine
'use strict';
let firebase = require('firebase');
exports.handler = function(event, context)
{
context.callbackWaitsForEmptyEventLoop = false;
firebase.initializeApp({
serviceAccount: {},
databaseURL: "https://harmanconnectedcar-180411.firebaseio.com/"
});
firebase.database().ref('events').once('value').then(function(snapshot) {
console.log("*************event**********************")
console.log (snapshot.val()) ;
context.succeed() ;
});
var starCountRef = firebase.database().ref('events' );
starCountRef.on('value', function(snapshot) {
console.log("*************snapshot*****snapshot*****************")
console.log (snapshot.val()) ;
context.succeed();
})
}
When i try starCountRef.on i am not able to see the logs printed
Once i put the lambda function in AWS and write to firebase from firebase console i am not able to see the events where do i need to see the logs how to check starCountRef.on event(i mean the real time logs)

You're starting two asynchronous listeners. Then when the first of them finishes you call context.succeed(). At that point Lambda terminates your function, so the second listener never completes.
To makes this code work, you need to ensure you only call context.succeed() when all of the data has loaded. An easy way to do this is by using Promise.all():
exports.handler = function(event, context)
{
context.callbackWaitsForEmptyEventLoop = false;
firebase.initializeApp({
serviceAccount: {},
databaseURL: "https://harmanconnectedcar-180411.firebaseio.com/"
});
var starCountRef = firebase.database().ref('events' );
var promises = [];
promises.push(firebase.database().ref('events').once('value'));
promises.push(starCountRef.once('value');
Promises.all(promises).then(function(snapshots) {
snapshot.forEach(function(snapshot) {
console.log(snapshot.val();
});
context.succeed();
});
}

You seem to be mixing up two technologies here.
The onWrite method is an construct of Cloud Functions for Firebase, which (as far as I know) cannot be deployed on Amazon lambda.
If you want to access your Firebase Realtime Database from Amazon Lambda, you can use the Firebase Admin SDK. But that doesn't include a way to trigger your code whenever the database is written.

Related

How to get AWS SQS queue ARN in nodeJS?

I'm trying to build an application with a basic client-server infrastructure. The server infrastructure is hosted on AWS, and when a client logs on, it sends a message to the server to set up various infrastructure considerations. One of the pieces of infrastructure is an SQS Queue that the client can poll from to get updates from the server (eventually I'd like to build a push service but I don't know how for right now).
I'm building this application in NodeJS using the Node AWS SDK. The problem I'm having is I need the queue ARN to do various things like subscribe the SQS queue to an SNS topic that the application uses, but the create queue API returns the queue URL, not ARN. So I can get the ARN from the URL using the getQueueAttributes API, but it doesn't seem to be working. Whenever I call it, I get undefined as the response. Here's my code, please tell me what I'm doing wrong:
exports.handler = (event, context, callback) => {
new aws.SQS({apiVersion: '2012-11-05'}).createQueue({
QueueName: event.userId
}).promise()
)
.then(data => { /* This has the Queue URL */
new aws.SQS({apiVersion: '2012-11-05'}).getQueueAttributes({
QueueUrl: data.QueueUrl,
AttributeNames: ['QueueArn']
}).promise()
})
.then(data => {
console.log(JSON.stringify(data)); /* prints "undefined" */
})
/* Some more code down here that's irrelevant */
}
Thanks!
const AWS = require('aws-sdk');
const sqs = new AWS.SQS();
exports.handler = async(event, context, callback) => {
var params = {
QueueUrl: 'my-queue-url',
AttributeNames: ['QueueArn']
};
let fo = await sqs.getQueueAttributes(params).promise();
console.log(fo);
};
and it printed
{
ResponseMetadata: { RequestId: '123456-1234-1234-1234-12345' },
Attributes: {
QueueArn: 'arn:aws:sqs:eu-west-1:12345:my-queue-name'
}
}
With the help of Ersoy, I realized that I was using block-formatting (with {}) to write my Promises, but I was never returning anything from those blocks. I had thought that the last value in the Promise block was the return value by default, but it seems that was not the case. When I added return before the SQS API command, then it worked (without using async/await).

How to Configure AWS X-Ray for node.js app not using Express middleware?

I am trying to integrate AWS X-Ray with my nodejs api hosted on AWS Lambda(serverless).
X-Ray works as intended for api using express middleware and able to see traces on AWS Console.
For async functions without express framework, I am facing issues while integration.
Tried enabling Manual mode, but facing- Lambda not supporting manual mode error.
Referred this - Developing custom solutions for automatic mode section but no luck.
Can someone help me out with this?
'use strict';
const AWSXRay = require('aws-xray-sdk-core');
const Aws = AWSXRay.captureAWS(require('aws-sdk'))
const capturePostgres = require('aws-xray-sdk-postgres');
const { Client } = capturePostgres(require('pg'));
module.exports.test = async (event, context) => {
var ns = AWSXRay.getNamespace();
const segment = newAWSXRay.Segment('Notifications_push');
ns.enter(ns.createContext());
AWSXRay.setSegment(segment_push);
.... };
So, when in Lambda, the SDK creates a placeholder (facade) segment automatically. More in-depth explanation here: https://github.com/aws/aws-xray-sdk-node/issues/148
All you need is:
const AWSXRay = require('aws-xray-sdk-core');
//lets patch the AWS SDK
const Aws = AWSXRay.captureAWS(require('aws-sdk'));
module.exports.test = async (event, context) => {
//All capturing will work out of box
var sqs = new AWS.SQS({apiVersion: '2012-11-05'});
var params = {...}
//no need to add code, just regular SQS call
sqs.sendMessage(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.MessageId);
}
});
//if you want to create subsegments manually simply do
const seg = AWSXRay.getSegment();
const subseg = seg.addSubsegment('mynewsubsegment');
subseg.close();
//no need to close the Lambda segment
};
Additional documentation here: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-tracing.html

Twilio Function not writing to Firebase

I'm trying to write to my Firebase database using a Twilio function (almost exactly the same as AWS Lambda function, if you're familiar with that), but I'm unable to do so. Firebase is generating a reference key for me, but nothing appears in my Firebase database when I check it. I don't see any error message from my function. Here's what I'm working with.
var firebase = require('firebase');
exports.handler = function(context, event, callback) {
var firebaseConfigs = {
apiKey: "[my_api_key]",
authDomain: "[my_domain].firebaseapp.com",
databaseURL: "https://[my_domain].firebaseio.com",
projectId: "[my_project_id]",
storageBucket: "[my_domain].appspot.com",
messagingSenderId: "[my_sender_id]"
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfigs);
console.log('Initialized Firebase app');
}
console.log('saving to firebase');
var ref = firebase.database().ref().push({
emailAddress: event.emailAddress,
test: 'test'
});
console.log('saved to ',ref.key)
setTimeout(function() {}, 3000);
callback();
};
In my function logs, I see the following:
Execution Started
Initialized Firebase app
saving to firebase
saved to [-LdVpr...]
Execution ended in 974.16ms using 97 MB
Clearly Firebase is generating a key for me, but the key [-LdVpr...] is not added to my database. What could be happening, and how can I further troubleshoot this?
With Execution ended in 974.16ms in the logs, sounds like
setTimeout(function() {}, 3000);
callback();
does not really do what you intended to do (wait for 3 seconds and then return to Twilio?).
I would try this ...
setTimeout(function() {
callback();
}, 3000);
... if that's what you'd like or need to do.
Update after reading this https://firebase.google.com/docs/reference/js/firebase.database.Reference.html#push
push() takes a second parameter, a "Callback called when write to server is complete.", so, I would also try something like this:
var ref = firebase.database().ref().push({
emailAddress: event.emailAddress,
test: 'test'
}, function (error) {
if (error) {
console.log(error);
callback();
} else {
console.log('Push successful');
callback();
}
});
maybe you don't need that 3 seconds thing at all.

AWS Lambda node-soap function (serverless framework)

I am testing a call to a SOAP service using node-soap library.
This works fine as a standalone node.js app and the SOAP service responds, however when I package the same code up as a serverless AWS lambda function (using serverless framework, but also executed directly in AWS lambda), it doesn’t appear to create the soap client.
Any thoughts on why this might be happening?
export async function main(event, context) {
var soap = require('soap');
var url = 'https://service.blah.co.uk/Service/Function.asmx?wsdl';
var soapOptions = {
forceSoap12Headers: true
};
var soapHeader = {
'SOAPAction': 'http://www.blah.co.uk/Services/GetToken'
};
var params = {
xmlMessage: message
};
console.log(JSON.stringify(params));
soap.createClient(url, soapOptions, function (err, client) {
//the serverless AWS lambda function never reaches this point (deployed and invoked locally)
console.log("In create client")
if (err) console.log(err);
client.addSoapHeader(soapHeader);
client.GetToken(params, function (err, data) {
console.log(data);
});
});
}
I have created a very minimal working example using async/await. Rather using the old style callback approach, just invoke soap.createClientAsync(url).
Here's the code:
'use strict';
const soap = require('soap');
module.exports.hello = async (event, context) => {
const url = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl';
const client = await soap.createClientAsync(url)
console.log(client)
return {
statusCode: 200,
message: 'It works!'
}
}
And here are the logs (partially):
EDIT: Function's output (via AWS's Lambda Console)
EDIT 2 - The REAL problem
Check the link above around async/await. The async keyword will execute asynchronously and will return a Promise. Since it's an asynchronous function, your Lambda is being terminated before it could actually execute your callback.
Using async/await will make your code simpler and will have you stop beating your brains out for such a small thing like this.

How do I upload node.js files to AWS Lambda and run successfully?

console.log('starting function')
exports.handle = function(event, context, callback){
var firebase = require('firebase');
var admin = require("firebase-admin");
var Mixpanel = require('mixpanel');
// initialize mixpanel client configured to communicate over https
var mixpanel = Mixpanel.init('********************', {
protocol: 'https'
});
var serviceAccount = require("productionKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "********************"
});
function getTotalUsers(){
admin.database().ref("users").once('value').then(function(snapshot) {
console.log("Total Users:", snapshot.numChildren());
mixpanel.track('Users Calculated', {
distinct_id: '9999',
"Total Users": snapshot.numChildren()
});
callback(null, snapshot.numChildren());
});
}
getTotalUsers();
}
My question is how do I actually get this working and running in AWS Lambda? I added in the first two lines and the callback because I assumed that is what is necessary for AWS. I'm new to this, but my script works just fine without those elements. I zip up the components, including the modules and package.json and the firebase production key and upload it as a Lambda function, when I test it though it just times out no matter what I change the max timeout to.
What am I doing wrong? I write tons of node.js scripts not too dissimilar from these and I'd love to know how I can get them running on AWS Lambda (scheduled). Thank you so much for your help in advance!
Lambda functions don't run like a script. They set things up and export a handler function, which Lambda invokes. The container will often persist, with Lambda re-invoking the handler with everything already initialized on subsequent (but not concurrent) invocations.
Untested, but to give you the idea, a high-level Lambdafication of your code might look more like this:
console.log('starting initialization')
var firebase = require('firebase');
var admin = require("firebase-admin");
var Mixpanel = require('mixpanel');
// initialize mixpanel client configured to communicate over https
var mixpanel = Mixpanel.init('********************', {
protocol: 'https'
});
var serviceAccount = require("productionKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "********************"
});
exports.handler = function(event, context, callback) => {
console.log('function invoked');
// google this -- you probably need this set to false, default is true
context.callbackWaitsForEmptyEventLoop = false;
admin.database().ref("users").once('value').then(function(snapshot) {
console.log("Total Users:", snapshot.numChildren());
mixpanel.track('Users Calculated', {
distinct_id: '9999',
"Total Users": snapshot.numChildren()
});
callback(null, snapshot.numChildren());
});
};

Resources