2

I've got a lambda function which is fired via API Gateway (this works).

The lambda then adds some data to the DynamoDB (this works)

Then I call a function I've created which sends data to the SQS

export const AddToQueue = async vehicleId => {
  const QueueParams = {
    DelaySeconds: process.env.QUEUE_DELAY,
    MessageAttributes: {},
  };

  QueueParams.MessageAttributes.vehicleId = {
    DataType: 'String',
    StringValue: vehicleId,
  };

  QueueParams.QueueUrl = 'my-queue-url';
  QueueParams.MessageBody = `vehicle: ${vehicleId} - ${new Date().toISOString()}`;

  try {
    await sqs.sendMessage(QueueParams).promise();
    console.log(`SQS:SUCCESS - AddToQueue - ${vehicleId}`);
  } catch (error) {
    console.log(`SQS:ERROR - AddToQueue - ${error}`);
  }
};

The first time this happens the message doesn't get to the SQS, but any other subsequent message is added to the queue and is handled. I've tried a whole bunch of things IAM permissions, settings on the queue, recreating the queue and none of this has helped.

I don't receive a success or error message so have no way to debug any issue.

Tom Maton
  • 1,564
  • 3
  • 23
  • 41
  • Which `console.log` is printed when you execute `AddToQueue` first time? – Pedro Arantes Jan 28 '20 at 12:32
  • @PedroArantes none of them are fired, nothing appears its like the function isn't fired. – Tom Maton Jan 28 '20 at 12:38
  • 1
    Please paste the code which is invoking `AddToQueue()` – MaiKaY Jan 28 '20 at 12:41
  • Do you have the whole Lambda code? The only difference between the first call and the next ones is that the variables are already defined. – Pedro Arantes Jan 28 '20 at 12:42
  • 3
    I'm pretty certain the issue is to do with some asynchronous part of your code not being awaited correctly, but we can only guess without seeing the rest of the code. The function you posted looks perfectly fine to me, but its usage might not be. – 404 Jan 28 '20 at 12:45
  • Also you (presumably) always have the option of temporarily adding lots of `console.log`s throughout your code so you can follow the code path. – 404 Jan 28 '20 at 12:48
  • @404 you are correct it was some asynchronous part of my code not being awaited correctly. – Tom Maton Jan 28 '20 at 12:54
  • @TomMaton if this is resolved then please ask 404 to write it up as an answer, if that was the answer, or write it you yourself so you can mark this question as answered. – jarmod Jan 28 '20 at 13:50
  • @404 could you please add an answer please and then I can mark it as resolved and correct answer - thanks. – Tom Maton Jan 28 '20 at 13:53

3 Answers3

4

I'm no expert in this but I've experienced this sort of behaviour before, where some asynchronous code in the first invocation either appears to not be executed or its execution appears to be delayed (e.g. actions performed by subsequent invocations appear to be based on data from previous call).

In all cases it was due to the asynchronous code not being awaited correctly. I don't know enough about both javascript and Lambda to explain the behaviour, especially the delays - can promises resolve after the handler has returned but while the container is still running? But what I do know is, if the lambda returns before the promises (async functions return promises) have been resolved (and therefore before the asynchronous code has completed running, which causes the observed behaviour of code being delayed or not executed), then they haven't been awaited correctly.

404
  • 8,022
  • 2
  • 27
  • 47
  • Is there any way we can set time or can make lambda to wait until all await calls are finished? – Cycl0n3 Nov 11 '20 at 08:12
  • @MukulMunjal Yes, just await them correctly. My experience of this issue as I said was this behaviour occurred when there were problems in the javascript code, usually some intricate nested stuff where some async functions were not awaited properly (or in other words, there were promises that went unresolved). Since I posted this I've had a lot more experience with both js and lambda, I know how to use them properly and we've never had this problem again. Which is to say, lambda works just fine, so if you experience this you have bugs in your js code. – 404 Nov 11 '20 at 08:25
  • Okay when i am running the code in my local its working fine. Second - when i execute lambda function twice within 2-3 mins second time it works fine. – Cycl0n3 Nov 11 '20 at 09:19
  • for (const [k, v] of mID) { if (k.match(/^[0-9a-fA-F]{24}$/)){ const us = await Model.findById(k); const u = await Model.findOne({ aId: us._id }); if (!u) { await Model.create({ aId: k, }); } else { u.today = 0; if (total > u.Limit) { await Model.findOneAndUpdate({ _id: u.atId }, { $set: {Limit: true } }); } await u.save(); } } } – Cycl0n3 Nov 11 '20 at 09:25
  • above is the code which i am using inside lambda function – Cycl0n3 Nov 11 '20 at 09:31
  • please reffer to full code https://stackoverflow.com/questions/64785383/lambda-function-not-working-in-first-trigger – Cycl0n3 Nov 11 '20 at 11:18
0

Probably you are not awaiting inside the async function you are calling AddToQueue()

If you are not calling AddtoQueue() inside an async function and awaiting it there, AddToQueue will run after that code is executed.

So let me give you an example.

You have 2 files in a test directory.

await.js main.js

await.js is :

module.exports = async ()=> {

await new Promise((res, rej)=>{
    setTimeout(()=>{
        res(console.log('Running'));
    }, 2000)
})

}

And the main.js

console.log('Hello')
require('./await')();

console.log('World')

When you run main.js, node main.js, Hello world will run, then after the promise resolves it will be pushed from the queue to your run stack and run the last.

Hello
World
// After 2 secs
Running

But instead if in main.js

(async ()=>{
console.log('Hello')
await require('./await')();

console.log('World')
})()

You let javascript engine know, this is a async function and await that module before running anything else, you would get the results that you expected.

Hello
// After 2 seconds
Running
World

Basically you are telling javascript engine I do not want you to run it your way, but run it my way.

frank3stein
  • 706
  • 2
  • 7
  • 16
0

I just had a very similar issue as this and my issue was related to not awaiting properly as @404 mentioned in the accepted answer.

Specifically, I was iterating over an array with forEach and calling await within the callback:

// causing weird behavior

async function invokeLambdas(teams) {
  teams.forEach(async (team) => {
    await utils.invokeLambda(team) // fn has a Lambda invoke in it
  });

I fixed this by removing the forEach and replacing it with a regular for-loop and awaiting inside as recommended here

async function invokeLambdas(teams) {
    for (const team of teams) {
        await utils.invokeLambda(team)
    }
 }
pbad
  • 55
  • 6
  • the problem with this method is that there is no parallelism. If you use Promise.all you will get better performance as all the calls will happen at once – user1099123 Jun 29 '21 at 04:17