Websocket on invoked lambda ignore message and send the last message received instead

0

When I invoke a lambda that send data to client through the websocket API, it doesn't send the actual message/payload but the last received.

Example:

  • Lambda 1 invoke Lambda 2 with payload "test1" > Lambda 2 send nothing to client
  • Lambda 1 invoke Lambda 2 with second payload "test2" > Lambda send 2 send "test1" to client
  • Lambda 1 invoke Lambda 2 with third payload "test3" > Lambda send 2 send "test2" to client

Enter image description here

My environnement:

  • Nodejs 16
  • lib websocket: AWS.ApiGatewayManagementApi.postToConnection

There is 0 cache on Websocket API. There is no Error, just weird behavior

3回答
0
承認された回答

I found the answer, change forEach loop to a for loop.

from:

items?.forEach(async (item) => {
  await apigwManagementApi.postToConnection(params).promise()
});

to:

for (const item of items) {
  await apigwManagementApi.postToConnection(params).promise()
}

I can't explain it, but it works, message are sent instantly to websocket.

回答済み 2年前
0

The issue is the way Node.js works. You are calling postToConnection, but what actually happens is that an event is added to the Node.js event loop. It is not performed immediately. You get to the end of the function and the run-time is frozen. At the point we do not handle the rest of the events until you invoke the function again. We then unfreeze the run-time and handle the next event.

To fix it, you should use await when calling postToConnection.

profile pictureAWS
エキスパート
Uri
回答済み 2年前
0

Hello @Uri, thank you for answering.

Unfortunately, this is already the case, I am already using async/await :

const AWS = require("aws-sdk");
const apigwManagementApi = new AWS.ApiGatewayManagementApi({
  endpoint: process.env.WEBSOCKET_DOMAIN_NAME
});
const dynamo = new AWS.DynamoDB.DocumentClient({ region: process.env.AWS_REGION });

/**
 * Send Websocket Message
 */
const websocketSendMessage = async (connectionId, data) => {
  const params = {
    ConnectionId: connectionId,
    Data: JSON.stringify(data)
  };
  await apigwManagementApi.postToConnection(params).promise();
  return;
};

/**
 * Handler
 */
const handler = async (event) => {
  const { userId, data } = event;

  // Retrieve all connectionId of user from DynamoDB
  let items;
  const dynamoItem = await dynamo.scan({
    TableName: process.env.DYNAMO_TABLE_NAME,
    FilterExpression: "userId = :userId",
    ExpressionAttributeValues: { ":userId": userId }
  }).promise();
  items = dynamoItem.Items;

  // Send websocket message for each websocket client of user
  items?.forEach(async (item) => {
    await websocketSendMessage(item.connectionId, data);
  });

  return { statusCode: 200 };
};

回答済み 2年前

ログインしていません。 ログイン 回答を投稿する。

優れた回答とは、質問に明確に答え、建設的なフィードバックを提供し、質問者の専門分野におけるスキルの向上を促すものです。

質問に答えるためのガイドライン

関連するコンテンツ