AWS Lambda Nodejs async.waterfall not executing MQTT Function - asynchronous

I am trying to use async.waterfall in the exports handler, and call functions sequentially. One of the function is related to MQTT message publishing. While the functions are being called, but when the MQTT function gets called, it just stops and not calls the require ('MQTT').
exports.handler = function(event, context) {
var async = require('async');
async.waterfall([
function(callback) {
retrieveEmailId(apiAccessToken,callback)
},
function(emailId, callback) {
retrieveDeviceDetails(callback)
},
function(deviceDetail, callback) {
publishMsg(callback)
}
], function(err, result) {
if (err) console.log('Error :: \n' + err);
});
}
function retrieveEmailId(accessToken, callback) {
var getEmailFromAlexaProfileObj = require('./GetEmailFromAlexaProfile');
getEmailFromAlexaProfileObj.doIt(accessToken, function(returnVal) {
console.log(returnVal);
callback(null, returnVal)
});
}
function retrieveDeviceDetails(callback) {
var getDevcieDetailsObj = require('./GetDevcieDetails');
getDeviceDetailsObj.doIt(null, function(returnVal) {
console.log(returnVal);
callback(null, returnVal)
});
}
function publishMsg() {
var mqtt = require('mqtt');
var options = {
clientId: "xxx",
username: "yyy",
password: "zzz",
clean: true
};
var client = mqtt.connect("mqtt://xxx.com", options)
client.on("connect", function () {
client.publish('xxx/yyy/L1', "1", options);
client.end();
});
}

Have you tried running the code locally using "lambda-local"? Does that sequence of call work along with the last one that is MQTT? What have you noticed when you invoke "require('mqtt')" within lambda?

Problem got resolved if the require variable is done prior to exports.handler.
for example....
var AWS = require('aws-sdk');
var async = require('async');
exports.handler = function(event, context) {
....
}

Related

SignalR connection closed but still works after angularjs scope destroy

I have a SignalR hub proxy in angularjs factory like this.
var app = angular.module('app');
app.factory("signalRHubProxy", ['$rootScope', "$timeout", function ($rootScope, $timeout) {
function signalRHubProxyFactory(serverUrl, hubName) {
var connection = $.hubConnection(serverUrl);
var proxy = connection.createHubProxy(hubName);
connection.disconnected(function () {
$timeout(function () {
connection.start();
}, 5000)
});
return {
on: function (eventName, callback) {
proxy.on(eventName, function (result) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
connection.start();
},
stop: function () {
connection.stop();
},
connection: connection
};
}
return signalRHubProxyFactory;
}]);
I used connection timeout because sometimes server does not listen, so I can retry.
I am using this factory in my controller:
app.controller("directiveController", function($scope, signalRHubProxy){
var signalRProxy = signalRHubProxy(
"url",
"hubname");
signalRHubProxy.on("datapush", function(data){
});
$scope.$destroy(function(){
signalRHubProxy.stop();
??? how to kill signalr hub
})
})
But when I remove my directive, signalR still works.
I believe when you call stop(), it calls disconnected event, which will just start the connection again. You might need to check if the disconnection was intentional (with a simple boolean variable), then just avoid restarting the connection:
app.factory("signalRHubProxy", ['$rootScope', "$timeout", function ($rootScope, $timeout) {
function signalRHubProxyFactory(serverUrl, hubName) {
var connection = $.hubConnection(serverUrl);
var proxy = connection.createHubProxy(hubName);
var manualStop = false;
connection.connected(function () {
manualStop = false; // reset variable if connected
});
connection.disconnected(function () {
if (manualStop)
return;
$timeout(function () {
connection.start();
}, 5000)
});
return {
on: function (eventName, callback) {
proxy.on(eventName, function (result) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
connection.start();
},
stop: function () {
manualStop = true;
connection.stop();
},
connection: connection
};
}
return signalRHubProxyFactory;
}]);
Also, make sure $scope.$destroy is being called.
Some people recommend calling $.connection.hub.stop(); instead of connection.stop();, although I don't really know whether it has some significant difference.

Using Meteor.wrapAsync to wrap a callback inside a method

This Meteor code is giving the error:
Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
I tried Meteor.bindEnvironment for no avail and want to try Meteor.wrapAsync. I could not figure it out from the docs. Could some one please help me with the syntax? thx
Meteor.methods({
'createTransaction':
function (nonceFromTheClient, Payment) {
let user = Meteor.user();
gateway.transaction.sale(
{
arg_object
},
function (err, success) {
if (!err) {
//do stuff here
}
}
);
}
});
Wrap in Meteor.wrapAsync
Meteor.methods({
'createTransaction':
function (nonceFromTheClient, Payment) {
this.unblock();
let user = Meteor.user();
var sale = Meteor.wrapAsync(gateway.transaction.sale);
var res = sale({arg_object});
future.return(res);
return future.wait();
}
});
Or try wrapping it in Fiber
var Fiber = Npm.require('fibers');
Meteor.methods({
'createTransaction': function (nonceFromTheClient, Payment) {
Fiber(function() {
let user = Meteor.user();
gateway.transaction.sale(
{
arg_object
},
function (err, success) {
if (!err) {
//do stuff here
}
}
);
}).run()
}
});
Update: Here's how I handle stripe with Async.runSync and Meteor.bindEnvironment
var stripe = require("stripe")(Meteor.settings.private.StripeKeys.secretKey);
Meteor.methods({
'stripeToken': function() {
this.unblock();
var future = new Future();
var encrypted = CryptoJS.AES.encrypt(Meteor.userId(), userIdEncryptionToken);
future.return(encrypted.toString());
return future.wait();
},
'stripePayment': function(token) {
var userId = Meteor.userId();
var totalPrice = 0;
//calculate total price from collection
totalPrice = Math.ceil(totalPrice * 100) / 100;
userEmail = Meteor.users.findOne({
'_id': userId
}).emails[0].address;
// Create a charge: this will charge the user's card
var now = new Date();
Async.runSync(function(done) {
var charge = stripe.charges.create({
amount: Math.ceil(totalPrice * 100), // Amount in cents // coverting dollars to cents
currency: "usd",
source: token,
receipt_email: userEmail,
description: "Charging"
}, Meteor.bindEnvironment(function(err, charge) {
if (err) {
//handle errors with a switch case for different errors
done();
} else {
//handle res, update order
}
}));
}); // Async.runSync
},
});

Angular client with signalR service not fire controller method

I have angular service where i got methods which are called from server when user connect or disconnect from my app
(function () {
//'use strict';
app.service('PrivateChatService', ['$rootScope', '$location', function PrivateChatService($rootScope, $location){
var online_users = [];
var proxy = $.connection.chatHub;
return {
addOnlineUser:
proxy.client.newOnlineUser = function (user) {
var newUser = ({
connectionId: user.ConnectionId,
UserName: user.UserName
});
online_users.push(newUser);
$.connection.hub.start()
},
removeOfflineUser: proxy.client.onUserDisconnected = function (id, user) {
var index = 0;
//find out index of user
angular.forEach(online_users, function (value, key) {
if (value.connectionId == id) {
index = key;
}
})
online_users.splice(index, 1);
$.connection.hub.start()
},
}
}])})();
Here i got controller method which i want to be fired when server calls newOnlineUser
PrivateChatService.newOnlineUser(function (user) {
$scope.online_users.push(newUser);
console.log("newOnlineUser finished");
});
So my question is. Is it possible to make with generated proxy or i have to use non-generated proxy access to those methods with which i am not very familiar.
With generated proxy as i show above it never reach my controller method to update my data in controller scope
Since nobody responded, what i find somehow odd. I found out this is working. I am not sure if this is good aproach since nobody answered and i didnt find any information how should this be solved.
app.service('PrivateChatService', ['$rootScope', '$location', function PrivateChatService($rootScope, $location){
var online_users = [];
var connection = $.hubConnection();
var proxy = connection.createHubProxy('chatHub');
function signalrCall(eventName, callback) {
proxy.on(eventName, function (user) {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(proxy, args)
})
});
connection.start();
}
return {
addOnlineUser: function (eventName, callback) {
signalrCall(eventName, callback);
},
getActiveUsers: function (eventName, callback) {
signalrCall(eventName, callback);
},
removeOfflineUser: function (eventName, callback) {
signalrCall(eventName, callback);
}
}
}])
angular controller methods
PrivateChatService.addOnlineUser("newOnlineUser", function (user) {
var newUser = ({
connectionId: user.ConnectionId,
UserName: user.UserName
});
$scope.online_users.push(newUser);
console.log("newOnlineUser finished");
});
PrivateChatService.getActiveUsers("getOnlineUsers", function (onlineUsers) {
angular.forEach($scope.online_users, function (scopeValue, scopeKey) {
//loop through received list of online users from server
angular.forEach(onlineUsers, function (serverListValue, serverListKey) {
if (!(serverListValue.ConnectionId == scopeValue.connectionId)) {
var newUser = ({
connectionId: serverListValue.ConnectionId,
UserName: serverListValue.UserName
});
$scope.online_users.push(newUser);
}
})
})
console.log("getOnlineUsers finished");
});
PrivateChatService.removeOfflineUser("onUserDisconnected", function (user) {
var index = 0;
//find out index of user
angular.forEach($scope.online_users, function (value, key) {
if (value.connectionId == user) {
index = key;
}
})
$scope.online_users.splice(index, 1);
});

how to push data back to client in meteor?

I have to make a aggregate query to DB when the user click on a button, however I don't know how to return that result back to the client since I'm doing an asynchronous request, this is part of my code:
//Server side
Meteor.startup(function() {
Meteor.methods({
getAllTotals: function (query){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var error = result = match = pipeline = '';
var group = {
$group: {
_id: null,
wall_clock: {
"$sum": "$wall_clock"
},
mem:{
"$sum": "$mem"
},
cpu:{
"$sum": "$cpu"
},
io:{
"$sum": "$io"
},
vmem:{
"$sum": "$vmem"
},
maxvmem:{
"$sum": "maxvmem"
}
}
};
if(typeof query.submission_time !== "undefined"){
match = {"$match": {submission_time: query.submission_time}};
pipeline = [match, group];
}else{
pipeline = [group];
}
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
console.log(result); // <<--- this is OK!
},
function(error) {
Meteor._debug( "Error doing aggregation: " + error);
}
)
);
return result; // <<--- this is empty
}
});
}
any suggestion? :-)
Short answer:
Solution you can find here:
How to get an async data in a function with Meteor
Detailed answer
using Meteor._wrapAsync
var aggregateTotal = function(callback){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
function (error, result){
if(error){
callback(error);
}else{
callback(null, result);
}
}
);
}
var aggregateTotalsSync = Meteor._wrapAsync(aggregateTotal);
Meteor.methods({
'getAllTotals': function(){
var result;
try{
result = aggregateTotalsSync();
}catch(e){
console.log("getAllTotals method returned error : " + e);
}finally{
return result;
}
}
});
using Futures (meteorPad example)
//Server side
Meteor.startup(function() {
var Future = Npm.require('fibers/future');
Meteor.methods({
getAllTotals: function (query){
var fut = new Future();
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
if(error){
fut.throw(error);
}else{
fut.return(result)
}
},
function (exception){
// caught exception is passed to this callback
fut.throw(exception);
}
)
);
return fut.wait();
}
});
}
Easy but a bit dirty way (but not so much if you think well about your architecture) -> send back the result trough Mongo.
You can even do it without Meteor.methods, with the request creation inserted in the database on the client, an observer on the server that check it and does the async task, and then write back the result in the database.

return values from server side meteor methods

Here is my code,
googleContacts:function()
{
var opts= { email: Meteor.user().services.google.email,
consumerKey: "xxxxxxxx",
consumerSecret: "xxxxxxxxxx",
token: Meteor.user().services.google.accessToken,
refreshToken: Meteor.user().services.google.refreshToken};
gcontacts = new GoogleContacts(opts);
gcontacts.refreshAccessToken(opts.refreshToken, function (err, accessToken)
{
if(err)
{
console.log ('gcontact.refreshToken, ', err);
return false;
}
else
{
console.log ('gcontact.access token success!');
gcontacts.token = accessToken;
gcontacts.getContacts(function(err, contact)
{
console.log(contact);
return contact;//want to return this value
})
}
});
}
I want to return the contact to the called method,as it is in a inner function i'm getting a bit difficult to return it to the called method.If it is in client side,then we can store the value in a session variable and we can return that,but this is a server side method,How to do this?
Use Futures:
Future = Npm.require('fibers/future');
Meteor.methods({
methodname: function() {
var fut = new Future();
apiCall(function(err, res) {
fut.return(...);
});
return fut.wait();
},
});

Resources