I'm creating an AWS lambda function that is supposed to regularly backup an AppSync API on S3 (it is fired by a CloudWatch schedule rule). It's based on a class that, for each API passed as the function args (using environment variables) runs a backup job for each element of the API.

If I run it using only node, it works without any issue.

However, when I deploy or test locally using the serverless framework (serverless deploy and serverless invoke local -f backup), the execution stops at the first asynchronous instruction in a scope other than that of the handler function, whether I use a callback, a Promise.then() or the async/await syntax.

I've considered, running multiple lambda functions for each part of the backup operation, but then I would lose the shared context, which I need to ensure that every part of the backup is done correctly.

In handler.js

  // for testing purposes
    // works, waits 5 seconds and execute the rest of the code
    console.log("here1");
    await new Promise(resolve => setTimeout(resolve, 5000));
    console.log("here2");
    const allBackups = apiIds.map(apiId => new Backup(apiId));
    allBackups.map(backup => backup.start());

Result => here1
[5 seconds wait]
here2

However, if I call a function that uses the asynchronous code, such as the start method of the Backup class (in the required Backup.js file), the following happens:



async start() {
        try {
            console.log("here3");
            const data = await this.AppSync.getGraphqlApi({ apiId: this.apiId }).promise();
            console.log("here4");

Result => here1
[5 seconds wait]
here2
here3
End of execution

I have all the required roles, and serverless reports no issues when deploying or invoking locally.

Here is my serverless.yml file:

service:  [name]

provider:
  name: aws
  runtime: nodejs8.10

functions:
  backup:
    handler: handler.backup
    environment:
     [env variables, they are parsed properly]
    timeout: 60
    event:
      schedule: [doesn't work as well, but it's not the issue here]
        name: daily-appsync-backup
        rate: cron(0 0 ** ? *)
        enabled: false
    role: [role]

Thanks in advance for your help !

1 Answers

0
Guy Mauve On Best Solutions

Ok so I've found a solution, I just did this:

    const allBackups = apiIds.map(apiId => new Backup(apiId));
    await Promise.all(allBackups.map(async backup => backup.start()));

It din't work because it reached the end of the handler function and did not care that there was other callbacks waiting. (I also learned that you could await an async function, and not just a Promise.)