0

My Lambda function is supposed to increment a value in a dynamodb table, I'm using the .update API as an atomic counter. The value is incremented twice! I tried to change the increment variable value and it always increments twice. For example: the value in my DynamoDB table is 2, and the increment value is 1. I test the Lambda function, and the dynamoDB value is 4 (instead of 3).

The same code (without the handler function) works successfully from outside Lambda (executed from VSCode using the JS SDK) What could be the issue?

'use strict';

const AWS = require("aws-sdk");
AWS.config.update({ region: "me-central-1" });

const docClient = new AWS.DynamoDB.DocumentClient();

exports.handler = async (event) => {
await docClient.update(
  {
    TableName: "visitor-counter-table",
    Key: {
      "visitor-counter": "counter",
    },
    UpdateExpression: "set #num = #num + :incr",
    ExpressionAttributeNames: {
      "#num": "number",
    },
    ExpressionAttributeValues: {
      ":incr": 1,
    },
  },
  (err, data) => {
    err ? console.log(err) : console.log(data);
  }
).promise();

  return {"statusCode": 200, "body": "number added to DDB Success"}
};

Here is the code i ran on VSCode:

const AWS = require("aws-sdk");
AWS.config.update({ region: "me-central-1" });

const docClient = new AWS.DynamoDB.DocumentClient();

docClient.update(
  {
    TableName: "visitor-counter-tbl",
    Key: {
      "visitor-counter": "counter",
    },
    UpdateExpression: "set #num = #num + :incr",
    ExpressionAttributeNames: {
      "#num": "number",
    },
    ExpressionAttributeValues: {
      ":incr": 1,
    },
  },
  (err, data) => {
    err ? console.log(err) : console.log(data);
  }
);
7
  • Can you please exactly show the code that you ran locally (i.e. without the handler function)? Commented Nov 10, 2022 at 16:13
  • ^ done, updated the question @ErmiyaEskandary Commented Nov 10, 2022 at 16:19
  • How do you trigger the lambda? Commented Nov 10, 2022 at 16:21
  • @BorislavStoilov for this purpose i use the TEST button in lambda, but i also trigger it using an API Gateway URL, which yields the same result. Commented Nov 10, 2022 at 16:23
  • 3
    @b_a9f It's because you're awaiting the promise, and using the callback at the same time - that's 2x. You should either await the promise OR use the callback not await the promise AND use the callback. I'll type up an answer soon :) glad it worked. Commented Nov 10, 2022 at 16:28

1 Answer 1

1

You're passing success and failure callbacks to docClient.update while also obtaining and awaiting a generated promise.

This means that ultimately you're triggering the update twice.

The reason why your local invocation works is that you're only passing the callbacks, and not asking for a promise (.promise()) and then awaiting it. This results in triggering the update once.

Either use await, or use callbacks - not both.

This should work:

await docClient.update(
  {
    TableName: "visitor-counter-table",
    Key: {
      "visitor-counter": "counter",
    },
    UpdateExpression: "set #num = #num + :incr",
    ExpressionAttributeNames: {
      "#num": "number",
    },
    ExpressionAttributeValues: {
      ":incr": 1,
    },
  }
).promise();
Sign up to request clarification or add additional context in comments.

2 Comments

It's interesting. I wonder why this is happening. Why would providing both a callback function and requesting a promise result in 2x API requests? That seems like a bug in the AWS SDK, or at least a very questionable outcome that would be worth preventing, if possible. Two completions from 1x API request (one a fulfilled promise and the other a callback) I could almost understand but not 2x API requests. Might have to dig into the code here to understand more.
OK, a call to service.action(params) returns an AWSRequest object that you have to call .send() on in order for the API request to actually be sent. But a call to service.action(params, callback) actually executes if (callback) request.send(callback), so the presence of the callback function sends the API request. Now, the .promise() method's code "sends the request and returns a promise", so it also sends the request. And that's why the API call happens twice if callback and promise() are both present.

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.