Search code examples
node.jsaws-lambdaasync-awaitserverless-framework

Problem/bug with Promise.race() on serverless(loading cache from previous calls)


The application is running in NodeJs and we are using Promise.race() to timeout the main promise, as show in the code (here the “mainPromise” is a generic promise for testing).


const promiseTimeout = new Promise((resolve, _) => {
  setTimeout(() => {
    resolve('promise Timeout');
  }, 20000);
});

const mainPromise = new Promise((resolve, _) => {
  setTimeout(() => {
    resolve('Main promise finished');
  }, 21000);
});

export const triggerVerifySls = async (event: any, context: any) => {
  context.callbackWaitsForEmptyEventLoop = false;

  const triggerStatus = await Promise.race([mainPromise, promiseTimeout]);

  const response = {
    statusCode: 200,
    body: JSON.stringify(triggerStatus),
  };

  return response;
};

When we deploy and call the function it works the first time, but in other calls, the Promise.race return the response of the first promise in the array.

Output with Promise.race([mainPromise, promiseTimeout])

$ Serverless reponse: promise Timeout
$ Serverless reponse: Main promise finished
$ Serverless reponse: Main promise finished
$ Serverless reponse: Main promise finished

Output with Promise.race([promiseTimeout, mainPromise])

$ Serverless reponse: promise Timeout
$ Serverless reponse: promise Timeout
$ Serverless reponse: promise Timeout
$ Serverless reponse: promise Timeout

It seems the function has the response cached, because it didn’t wait 20 seconds after the first call: screenshot

  • Does the function cache the response?
  • Does the function support Promise.race?

SERVERLESS.YML

frameworkVersion: '2'

provider:
  name: aws
  runtime: nodejs14.x
  memorySize: 2052
  timeout: 30
  region: us-east-1

functions:
  triggerVerifySls:
    handler: src/serverless/triggerVerifySls.triggerVerifySls
    events:
      - http:
          path: triggerVerifySls
          method: post

Solution

  • yeah like the comments say, make your fake promise's functions instead of const promises:

    const promiseTimeout = () => new Promise((resolve, _) => {
      setTimeout(() => {
        resolve('promise Timeout');
      }, 20000);
    });
    
    const mainPromise = () => new Promise((resolve, _) => {
      setTimeout(() => {
        resolve('Main promise finished');
      }, 21000);
    });
    

    Then call it like so:

    const triggerStatus = await Promise.race([mainPromise(), promiseTimeout()]);
    ...