Node AWS Lambda not executing some asynchronous code

371 views Asked by At

I am using the Serverless Framework with the serverless-webpack plugin, Prisma, and Node 12.x on AWS. I have several lambdas that each execute some async code, but some of the code doesn't seem to execute (or promises fulfill). The code works perfectly locally, but not when deployed on AWS.

Example lambda with relevant comments inline:

"use strict";

import { PrismaClient } from "@prisma/client";
import fetch from "node-fetch";

const prisma = new PrismaClient();

module.exports.handler = async (event, context, callback) => {
  try {
    const users = await prisma.user.findMany();
    console.log(`Users: ${JSON.stringify(users)}`); // shows properly in Lambda logs

    users.map(async (user) => {
      const res = await fetch(`...`); // doesn't seem to execute on AWS but does locally
      const data = await res.json();
      const query = await prisma.user.update({...}); // doesn't seem to execute on AWS but does locally

      console.log(data); // doesn't show up in Lambda logs
      console.log(query); //doesn't show up in Lambda logs

    });

    // shows properly in Lambda logs
    console.log(
      `Completed ${context.functionName} at ${new Date().toLocaleString()}`
    );
  } catch (err) {
    console.log(`ERROR: ${context.functionName} failed with error ${err}`);
  }
};

webpack.config.js:

const path = require("path");
const slsw = require("serverless-webpack");
const nodeExternals = require("webpack-node-externals");
const CopyWebpackPlugin = require("copy-webpack-plugin");

module.exports = {
  context: __dirname,
  mode: slsw.lib.webpack.isLocal ? "development" : "production",
  entry: slsw.lib.entries,
  devtool: slsw.lib.webpack.isLocal
    ? "cheap-module-eval-source-map"
    : "source-map",
  resolve: {
    extensions: [".mjs", ".json", ".ts"],
    symlinks: false,
    cacheWithContext: false,
  },
  output: {
    libraryTarget: "commonjs",
    path: path.join(__dirname, ".webpack"),
    filename: "[name].js",
  },
  target: "node",
  externals: [nodeExternals()],
  module: {
    rules: [
      // all files with `.ts` or `.tsx` extension handled by `ts-loader`
      {
        test: /\.(tsx?)$/,
        loader: "ts-loader",
        exclude: [
          [
            path.resolve(__dirname, "node_modules"),
            path.resolve(__dirname, ".serverless"),
            path.resolve(__dirname, ".webpack"),
          ],
        ],
        options: {
          transpileOnly: true,
          experimentalWatchApi: true,
        },
      },
    ],
  },
  plugins: [
    new CopyWebpackPlugin({ patterns: ["prisma/schema.prisma"] }),
  ],
};

I have also tried without the try/catch block, and have increased the lambda timeout in serverless.yml. I thought maybe it had to do with the nested async (user.map(async ...)), but I am not sure. The CloudWatch logs for the lambdas show no errors, and only show the console.log()s outside of the map function as indicated in the code. Any help is greatly appreciated. Thank you so much!

EDIT: I am now receiving an error in the CloudWatch logs: ERROR: [LAMBDA_NAME] failed with error FetchError: request to [ENDPOINT] failed, reason: connect ETIMEDOUT [IP_ADDRESS]:443. I think this is a separate issue, however. The solution was to change users.map(async (user) => {...} to for (const user of users) {...} as @CyberEternal suggested.

1

There are 1 answers

1
CyberEternal On BEST ANSWER

The issue related to the async function in the map. Actually, it's not working. You can try the "for" loop. It's working 100%.

Try this way

"use strict";

import { PrismaClient } from "@prisma/client"; import fetch from "node-fetch";

const prisma = new PrismaClient();

module.exports.handler = async (event, context, callback) => {   try {
    const users = await prisma.user.findMany();
    console.log(`Users: ${JSON.stringify(users)}`); // shows properly in Lambda logs

    for (const user of users) {
      console.log('user: ', user); // doesn't show up in Lambda logs
      const res = await fetch(`...`); // doesn't seem to execute on AWS but does locally
      const data = await res.json();
      const query = await prisma.user.update({ ...}); // doesn't seem to execute on AWS but does locally

      console.log('data: ', data); // doesn't show up in Lambda logs
      console.log('query: ', query); //doesn't show up in Lambda logs
    }
    // shows properly in Lambda logs
    console.log(
      `Completed ${context.functionName} at ${new Date().toLocaleString()}`
    );   } catch (err) {
    console.log(`ERROR: ${context.functionName} failed with error ${err}`);   } };

And it will be better if you use a separate function for the update process. Like this way

"use strict";

import { PrismaClient } from "@prisma/client";
import fetch from "node-fetch";

const prisma = new PrismaClient();

module.exports.handler = async (event, context, callback) => {
  try {
    const users = await prisma.user.findMany();
    console.log(`Users: ${JSON.stringify(users)}`); // shows properly in Lambda logs
    await updateUser(users);
    // shows properly in Lambda logs
    console.log(
      `Completed ${context.functionName} at ${new Date().toLocaleString()}`
    );
  } catch (err) {
    console.log(`ERROR: ${context.functionName} failed with error ${err}`);
  }
};

const updateUser = async users => {
  if (!users || !users.length) throw new Error('Users not found');
  for (const user of users) {
    console.log('user: ', user); // doesn't show up in Lambda logs
    const res = await fetch(`...`); // doesn't seem to execute on AWS but does locally
    const data = await res.json();
    const query = await prisma.user.update({ ...}); // doesn't seem to execute on AWS but does locally

    console.log('data: ', data); // doesn't show up in Lambda logs
    console.log('query: ', query); //doesn't show up in Lambda logs
  }
  return 'Updated'
}