Executing Lambda invocations concurrently can result in an empty payload being returned

To ensure the effectiveness of my lambdas, I constructed a series of canaries for testing purposes. These canaries follow a fat-lambda approach for simplicity, utilizing a single parameter to indicate which canary should be triggered.

const { isLambda } = require('../helpers/isLambda');
const { authorizerSuccess } = require('./authorizer-success');
const { authorizerFailure } = require('./authorizer-failure');
const log = require('SyntheticsLogger');

exports.handler = async () => {
  const purpose = process.env.CANARY_PURPOSE;
  log.info('Initiating canary execution: ', purpose);
  switch (purpose) {
    case 'authorizer-success':
      await authorizerSuccess();
      break;
    case 'authorizer-failure':
      await authorizerFailure();
      break;
    default:
      throw new Error(`Unknown purpose: ${purpose}`);
  }
  log.info('Canary executed successfully');
};

if (!isLambda) {
  exports.handler();
}

The authorization processes for success and failure are relatively straightforward; both involve invoking a Lambda function that validates the parameter and provides a payload with data validity information.

// authorizer-success.js

const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda');
const { jsonData } = require('../helpers/getVariables');
const log = require('SyntheticsLogger');
const authorizerSuccess = async function () {
  if (!jsonData.authorizer_arn) {
    throw new Error('Authorizer ARN is not defined');
  }
  if (!jsonData.authorizer_payload) {
    throw new Error('Authorizer payload is not defined');
  }

  const invokeParams = {
    FunctionName: jsonData.authorizer_arn,
    Payload: JSON.stringify({ ...jsonData.authorizer_payload }),
    InvocationType: 'RequestResponse',
  };

  const input = new InvokeCommand(invokeParams);
  log.info({ invokeParams });

  const client = new LambdaClient();
  const data = await client.send(input);
  log.info({ data });
  const jsonString = Buffer.from(data.Payload).toString('utf8');

  log.info({ jsonString });
  if (!jsonString || jsonString.length === 0) {
    throw new Error('No response from authorizer');
  }
  const parsedData = JSON.parse(jsonString);

  log.info({ parsedData });
  if (parsedData.statusCode === 403) {
    throw new Error('Login failed, check credentials');
  }
  return 'Successful check on Authorizer-success canary!';
};

exports.authorizerSuccess = authorizerSuccess;

The autorization-fail canary performs similarly but alters the payload with incorrect values.

Upon deployment, I observed that they consistently executed sequentially, with the second one always returning an empty payload in the Lambda response.

// log.info({data})

2024-05-22T19:27:15.283Z    aaaa8d-a0af-4248-843e-3aaaa11b  INFO    {
  data: {
    '$metadata': {
      httpStatusCode: 200,
      requestId: '8aaaad-3408-4caf-90e2-31aaaa7a',
      extendedRequestId: undefined,
      cfId: undefined,
      attempts: 1,
      totalRetryDelay: 0
    },
    ExecutedVersion: '$LATEST',
    Payload: Uint8ArrayBlobAdapter(0) [Uint8Array] [],
    StatusCode: 200
  }
}

Interestingly, the logs within the authorizer Lambda correctly display the response Payload.

The timestamps within the authorizer Lambda appear accurate: displaying the response payload, followed by the 'invoker' Lambda receiving the response (sans Payload) approximately 10 milliseconds later.

Furthermore, I experimented with updating the canary switch to concurrently call authorizerSuccess() multiple times. In this scenario, when invoking the lambda 5 times, only 2 of them randomly receive the response payload, while the rest receive an empty payload response. The statusCode consistently registers as 200.

Answer №1

After thorough investigation, it was determined that the issue stems from using AWS-SDK v3 with runtime.SYNTHETICS_NODEJS_PUPPETEER_X_Y (the canary runtime for nodejs). By downgrading to v2, the error has been resolved.

Further research revealed two other instances of similar errors:

Updating aws-sdk v2 to v3 breaks DynamoDB call in Synthetics Canary

https://github.com/aws/aws-sdk-js-v3/issues/5892

It appears that this is an AWS bug that currently has no solution other than reverting back to v2.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

TypeScript and Angular: Harnessing the Power of Directive Dependency Injection

There are multiple approaches to creating Angular directives in TypeScript. One elegant method involves using a static factory function: module app { export class myDirective implements ng.IDirective { restrict: string = "E"; replace: ...

"Handling dependency injection with cyclic dependencies along with a custom implementation of HTTP and ConfigService

I am currently working on implementing a ConfigService to retrieve the appropriate configuration for each environment within the project. However, I have run into an issue with cyclic dependencies. (index):28 Error: (SystemJS) Provider parse errors: C ...

Is it possible to extract a single element from an array that is stored as a standard Observable?

Currently, I am using a regular observable instead of an observableArray. This observable keeps an array of elements which is defined as follows: public arrayOfItems: IArrayItem[]; public arrayOfItems$: BehaviorSubject<IArrayItem[]> = new BehaviorSu ...

Angular 5 - Issue with Conditional Validator Functionality Being Ineffective

If the email field is not left empty, then the re-email field must be marked as 'required'. In order to achieve this functionality, I have implemented conditional validators for the re-email field using the code snippet below: HTML <div cla ...

Preventing Multiple Login Attempts in Angular.js Using Typescript

Is there a way to maintain the user login attempts limit even after page refresh? login() { /* Check if user has fewer than 5 failed login attempts */ if (this.failedAttempts < 4) { this.auth.login(this.credentials).subscribe(() => { this.rou ...

Having trouble getting Tinymce to appear on the screen

I am currently attempting to install TinyMCE for use with my text editor in order to provide the user with a text box similar to the one on Stack Overflow. However, I am encountering an issue where it is not displaying as expected. In the header of my ind ...

What is the reason for the inability of `Array<Value>, Value` to properly retrieve the type of the array value?

I am encountering an issue with the type declaration below: function eachr<Subject extends Array<Value>, Value>( subject: Subject, callback: ( this: Subject, value: Value, key: number, subject: Subject ...

Integration of Mocha with WebStorm

WebStorm offers a useful feature that adds a small arrow next to describe() and it() keywords when writing tests with Mocha, allowing for easy manual execution. However, there is a challenge: I require additional setup before each test, leading me to use ...

Determining the inner type of a generic type in Typescript

Is there a way to retrieve the inner type of a generic type in Typescript, specifically T of myType<T>? Take this example: export class MyClass { myMethod(): Observable<{ prop1: string, ... }> { .... } } type myClassReturn = ReturnTy ...

How can a Firestore Timestamp object be correctly created within a rules test data set?

I am in the process of writing tests for Firestore rules, focusing on testing rules that control when actions can be executed based on a timestamp stored in the document. It is important to note that the rules will utilize rules.Timestamp rather than Java ...

Issues with TypeScript Optional Parameters functionality

I am struggling with a situation involving the SampleData class and its default property prop2. class SampleData { prop1: string; prop2: {} = {}; } export default SampleData; Every time I attempt to create a new instance of SampleData without sp ...

Can I combine tuple types in Typescript?

type A1 = ['x','y','z'] type A2 = ['u','v','w'] type AN = [.., .., ..] type C = Combine<A1,A2,...,AN> //or Combine<[A1,A2,...,AN]> //resulting in ['x','y','z& ...

Tips for submitting a request following a change in the variable

I am in the process of developing a React application and I have implemented Auth0 for authentication. My goal is to initiate an HTTP request upon page refresh, but only if the variable isLoading is false. This way, I can access the user object once the ...

Guide on setting up factories with pre-existing relationships in MIKRO-ORM

Hey there! I'm currently exploring how to set up a factory and establish relationships between models. For instance, I have a UserFactory that corresponds to the User entity which is connected to the userType table. However, in the factory, I'm ...

ESLint in Typescript is flagging an error for unused variables when using callback functions with parameters

Currently, I am facing an issue with the following demo code: const callFnWithArgs = (callback: (a: string, b: number) => void) => async (a: string, b: number): Promise<void> => { try { await callback( ...

Stop receiving notifications from Angular valueChanges

In my service class, I have the following code snippet: class UserFormService { createUserForm() { const userForm = new FormGroup({ firstName: new FormControl(), lastName: new FormControl(), displayName: new ...

Rearrange the parent object's structure based on the data and length of the child array

Is it possible to restructure parent data based on the child array data and its length? Should I stick with an array structure or consider changing the object array from the backend? No IDs are present in the child arrays. This is what has been accomplis ...

Creating an asynchronous function that can handle a variable number of arguments and returns the appropriate data type

I'm looking to create a helper function that can wrap an existing async function with a variable number of arguments, allowing me to call it like this: const submit = wrapLoading(async (values: string[]) { // await something with values return tru ...

My initial venture into Solidity DApp development, Encounter of an Unresolved Runtime

As I embark on developing my inaugural Solidity DApp using Next.js and Hardhat, I've encountered a perplexing error. After successfully deploying my contract on a local blockchain via npx hardhat node, the issue arises when calling the getProposalCoun ...

Oops! There seems to be an issue with locating a differ that supports the object '[object Object]' of type 'object', like an Array

I'm currently encountering an error that reads: (ERROR Error: NG02200: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables, such as Arrays. Did you mean to use the key ...