How can I console.log the promise stored in a promise
variable? I want to later assign that to a variable.
function getMetricFilters() {
const promise = new Promise(function(resolve, reject) {
exec("aws cloudwatch list-metrics --namespace AWS/ApiGateway | jq -r .Metrics[].Dimensions[].Name | sort -u", (error, stdout, stderr) => {
if (error) {
console.error(`error: ${error.message}`);
//return errorResponse(500, 'Error running migration.');
}
if (stderr) {
console.log(`stderr: ${stderr}`);
//return errorResponse(500, 'Error running migration.');
}
console.log(`stdout: ${stdout}`);
//return okResponse(200, 'Migration successfully.');
})
})
return promise
}
getMetricFilters() // I want the result of promise to be printed out or store it in a variable.
If I don't use the getMetricFilters
function then it prints out stdout
value. But if use the function, then nothing is printed out.
Full code:
var AWS = require('aws-sdk');
AWS.config.region = 'ap-south-1';
var lambda = new AWS.Lambda();
const exec = require("child_process").exec;
exports.handler = function(event, context, callback) {
console.log("AWS lambda and SNS trigger ");
console.log(event);
const promise = new Promise(function(resolve, reject) {
exec("ls /usr/bin/", (error, stdout, stderr) => {
if (error) {
console.error(`error: ${error.message}`);
//return errorResponse(500, 'Error running migration.');
}
if (stderr) {
console.log(`stderr: ${stderr}`);
//return errorResponse(500, 'Error running migration.');
}
console.log(`stdout: ${stdout}`);
//return okResponse(200, 'Migration successfully.');
})
})
return promise // Right now it ends here. But I intened to do other things instead of return and end here.
var sns = JSON.parse(event.Records[0].Sns.Message);
var sns_MetricName = sns.Trigger.MetricName;
var sns_NameSpace = sns.Trigger.Namespace;
console.log(sns.Trigger.Dimensions)
function dimensionValue(name) {
console.log("Testing")
var dimensionsValue = sns.Trigger.Dimensions.find(dimension => dimension.name === name).value
return dimensionsValue
}
function dimensionName(name) {
return sns.Trigger.Dimensions.find(dimension => dimension.name === name)
}
if (sns.Trigger.Namespace == "AWS/S3") {
var sns_DimensionsValue = dimensionValue('BucketName') '_' dimensionValue('StorageType')
}
console.log("Printing SNS DimensionsValue")
console.log(sns_DimensionsValue)
var zabbix_Hostname = JSON.stringify(sns_NameSpace.replace("/", "_"));
var zabbix_Key = "AWS[" sns_DimensionsValue '_' sns_MetricName "]"
var zabbix_Key = JSON.stringify(zabbix_Key);
console.log("Printing SNS")
console.log(event.Records[0].Sns.Message)
var params = {
FunctionName: 'zabbixPy', // the lambda function we are going to invoke
InvocationType: 'RequestResponse',
LogType: 'Tail',
Payload: `{ "Host": ${zabbix_Hostname}, "Key": ${zabbix_Key}, "Value": "1"}`
};
lambda.invoke(params, function(err, data) {
if (err) {
context.fail(err);
} else {
context.succeed('zabbixPy said ' data.Payload);
}
})
console.log("End of function");
};
CodePudding user response:
Make a re-usable helper function that encapsulates exec()
in a promise:
function execAsync(cmdline) {
return new Promise((resolve, reject) => {
exec(cmdline, (error, stdout, stderr) => {
if (error) reject({error, stdout, stderr});
else resolve({stdout, stderr});
});
});
}
Make a function for your cloudwatch command:
function getMetricFilters() {
return execAsync("aws cloudwatch list-metrics --namespace AWS/ApiGateway | jq -r .Metrics[].Dimensions[].Name | sort -u");
}
Use it:
getMetricFilters()
.then(({stdout, stderr}) => {
okResponse(200, 'Migration completed successfully.');
})
.catch(({error, stdout, stderr}) => {
console.error(`error: ${error.message}`);
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
errorResponse(500, 'Error running migration.');
});
Mixing node-style callbacks and promises usually does not end well.
Since your exports.handler
is a callback-based function, and all your other functions (like exec()
and lambda.invoke()
) are callback-based, I would keep the entire code callback-based.
The async
module offers useful helpers for this, such as waterfall()
, which executes a list of asynchronous functions one after another, passing the result(s) of the previous to the next.
exports.handler = function (event, context, callback) {
async.waterfall([
// 1. parse SNS message (throw if invalid/unexpected)
(callback) => {
const sns = JSON.parse(event.Records[0].Sns.Message);
console.log(1, sns);
const Namespace = sns.Trigger.Namespace;
if (Namespace !== "AWS/S3") throw new Error('Unexpected Namespace: ' Namespace);
const msgData = {
Namespace: Namespace,
MetricName: sns.Trigger.MetricName,
BucketName: sns.Trigger.Dimensions.find(where('name', 'BucketName')).value,
StorageType: sns.Trigger.Dimensions.find(where('name', 'StorageType')).value
};
callback(null, msgData);
},
// 2. run cloudwatch command
(msgData, callback) => {
console.log(2, msgData);
const cmdline = "aws cloudwatch list-metrics --Namespace AWS/ApiGateway | jq -r .Metrics[].Dimensions[].Name | sort -u";
exec(cmdline, (err, stdout, stderr) => {
if (err) return callback(err);
callback(null, msgData, stdout, stderr);
});
},
// 3. run zabbixPy
(msgData, stdout, stderr, callback) => {
console.log(3, msgData, stdout);
lambda.invoke({
FunctionName: 'zabbixPy',
InvocationType: 'RequestResponse',
LogType: 'Tail',
Payload: JSON.stringify({
Host: msgData.Namespace.replace("/", "_"),
key: `AWS[${msgData.BucketName}_${msgData.StorageType}_${msgData.MetricName}]`,
Value: "1"
})
}, callback);
},
// 4. next step...
(zabbixResponse, callback) => {
console.log(4, zabbixResponse.Payload);
// ...
callback(null, 'All done.');
},
], (err, result) => {
if (err) {
console.error(err);
context.fail(err);
callback(err);
return;
}
console.log(result); // 'All done.'
// don't forget to call the main callback here
});
};
The alternative would be to convert all asynchronous functions in that code path to promise-based functions. Not sure if that's less work.