0

I’m newish to Node Js and Async processing. I’m working on a discord bot that is integrated with AWS. My problem is everything I have tried, async/await or wrapping in Promise’s has not fixed the issue of the rest of the code executing before the async process finishes. AWS calls are mostly async in general, but I’m trying to create a sync process (checking is an item already exists before adding it). Right now, the check is not finishing in time, so the item gets re-added.

EDIT BELOW IS MY EDITED CODE AND OUTPUT

const AWSUtil = require("../utils/aws/awsUtil")

module.exports = async (client, message) => {
  
  const aws = new AWSUtil()
  const tableName = "Discord-Server"
  
  let serverName = message.guild.name.replace(/[^a-zA-Z ]/g, "").replace(' ', '-')
  let serverID = message.guild.id
  
  if (message.member.hasPermission("ADMINISTRATOR")){
    var doesExist = await doesServerExist()
    console.log(`doesExist ----- ${doesExist}`)
    if(!doesExist){
      console.log("5 server is not already enrolled, adding the server...")
      aws.addDynamoDBItem(addServerParams())
      console.log("6 server successfully added")
      message.reply(`${message.guild.name} has been successfully enrolled to SMSAlert!`)
    } else {
      console.log("5 server already enrolled...")
      message.reply(`${message.guild.name} is already enrolled to SMSAlert.`)
    }
   
    } else {
      return message.reply("You do not bave permissions to enroll the server.")
    }

async function doesServerExist(){
  console.log("1 Calling AWS util")
  var response = await aws.getDynamoDBItem(checkExistParams())
  //The below line never prints
  console.log("4 Returning if server exists")
  console.log(Object.keys(response))
  return !Object.keys(response).length == 0
}

function addServerParams(){
return params = {
    TableName:tableName,
    Item:{
        "server-id": serverID,
        "server-name": serverName,
        "topics":[]
    }
};
}

function checkExistParams(){
  return params = {
    TableName: tableName,
    Key:{
        "server-id": { S: serverID }
    }
};
}

}

THE BELOW IS MY AWSUTIL CLASS

var AWS = require('aws-sdk');

class AWSUtil {
  
  constructor(){
    AWS.config.loadFromPath('./config/aws/config.json');
  }
  
  async getDynamoDBItem(params){
    console.log("2 Get Dynamo Item...")
    const docClient = new AWS.DynamoDB.DocumentClient();
    
    const awsRequest = await docClient.scan(params);
    const result = await awsRequest.promise();
    console.log(result.Items);
    console.log("3 Returning getItem data")
    return results.Items
  }
  
  async addDynamoDBItem(params){
    console.log("Adding a new item...");
    var docClient = new AWS.DynamoDB.DocumentClient();
    const awsRequest = await docClient.put(params);
    const result = await awsRequest.promise();
    console.log("Added item:", JSON.stringify(result))
    //docClient.put(params, function(err, data) {
    //if (err) {
        //console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
    //} else {
        //console.log("Added item:", JSON.stringify(data, null, 2));
    //}
//});
  }
  
  removeDynamoDBItem(params){
    console.log("Attempting to delete...");
    var docClient = new AWS.DynamoDB.DocumentClient();
docClient.delete(params, function(err, data) {
    if (err) {
        console.error("Unable to delete item. Error JSON:", JSON.stringify(err, null, 2));
    } else {
        console.log("DeleteItem succeeded:", JSON.stringify(data, null, 2));
    }
});
  }
}

module.exports = AWSUtil

THE BELOW IS MY OUTPUT

1 Calling AWS Util 
2 Get Dynamo Item...
[
My item
]
3 Returning getItem data

I have the below in my main file.

if (message.member.hasPermission("ADMINISTRATOR")) {
  if (!doesServerExist()) {
    console.log("server is not already enrolled, adding the server...");
    aws.addDynamoDBItem(addServerParams());
    console.log("server successfully added");
    //return message.reply(`You have successfully enrolled ${message.guild.name} to SMSAlerts.`)
  } else {
    console.log("server already enrolled...");
    //return message.reply(`${message.guild.name} is already enrolled to SMSAlert`)
  }
} else {
  return message.reply("You do not bave permissions to enroll the server.");
}

function isEmptyObject(obj) {
  return !Object.keys(obj).length;
}

function doesServerExist() {
  return isEmptyObject(aws.getDynamoDBItem(checkExistParams()));
}

And below is my AWS call

async getDynamoDBItem(params) {
    console.log("Get Dynamo Item...")
    var dynamodb = new AWS.DynamoDB({
        apiVersion: '2012-08-10'
    });
    var response = null
    await dynamodb.getItem(params, function(err, data) {
        if (err) {
            console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
        } else {
            response = data
        }
    }).promise()
    return response
}

2 Answers 2

1

I am not a AWS user, but if you have used a Promise in one step of your tasks, it usually means you need to handle the async procedure for every steps. Eg:

async function doesServerExist(){
  const result = await aws.getDynamoDBItem(checkExistParams())
  return isEmptyObject(result)
}

Of course, if you want to get the result of doesServerExist, you should also use await before its invoke, to get the result asynchronously.

Sign up to request clarification or add additional context in comments.

1 Comment

I edited my code above. I am getting the response from AWS in order, but after AWS returns with the item I am looking for, the output freezes and doesn’t continue. I’m assuming this is related to the awaits I have?
0

currently checking the AWS documentation

https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Request.html#promise-property

it seems like you actually don't need to pass a callback function to dynamodb.getItem if you using promise but rather wait for the promise to resolve / fail.

so this line of codes is wrong

await dynamodb.getItem(params, function(err,data){
  if (err) {
    console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
  } else {
    response = data
  }
}).promise()

and should be like this using promises (1st argument successfully resolve, 2nd one is a failure of the request base on the documentation)

dynamodb.getItem(params).promise()
 .then( function(data) {
   response = data;
 }, function(err) => {
   console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
 })

and not sure if catch method can be use instead of the 2nd argument but in async/await implementation see below

 try {
   const response = await dynamodb.getItem(params).promise()
 } catch(err) {
  console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
 }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.