我具有以下功能,可从aws SQS获取消息,问题是我一次收到一个消息,并且希望获取所有消息,因为我需要检查每条消息的ID:
function getSQSMessages() {
const params = {
QueueUrl: 'some url',
};
sqs.receiveMessage(params, (err, data) => {
if(err) {
console.log(err, err.stack)
return(err);
}
return data.Messages;
});
};
function sendMessagesBack() {
return new Promise((resolve, reject) => {
if(Array.isArray(getSQSMessages())) {
resolve(getSQSMessages());
} else {
reject(getSQSMessages());
};
});
};
函数 sendMessagesBack()用于另一个异步/等待函数。 我不确定如何获取所有消息,因为我一直在寻找如何获取消息,人们提到了循环,但是我无法弄清楚如何在我的情况下实现它。 我假设必须将 sqs.receiveMessage()放入循环中,但是随后我对需要检查的内容以及何时停止循环感到困惑,这样我才能获得每条消息的ID?
如果有人有任何提示,请分享。 谢谢。
答案 0 :(得分:2)
我建议您使用Promise api,它将使您可以立即使用async / await语法。
const { Messages } = await sqs.receiveMessage(params).promise();
// Messages will contain all your needed info
await sqs.sendMessage(params).promise();
通过这种方式,您将不需要用Promises包装回调API。
答案 1 :(得分:2)
SQS在响应中返回的消息不超过10条。要获取所有可用消息,您需要递归调用getSQSMessages函数。 如果您从getSQSMessages返回承诺,则可以执行以下操作。
getSQSMessages()
.then(data => {
if(!data.Messages || data.Messages.length === 0){
// no messages are available. return
}
// continue processing for each message or push the messages into array and call
//getSQSMessages function again.
});
答案 2 :(得分:1)
我们永远不能保证将所有消息都放入队列中,除非获得其中的一部分,然后将它们从队列中删除-这样才能确保下一个请求返回不同的记录选择。
每个请求将返回“最多” 10条消息,如果您不将其删除,则很有可能下一个对“最多” 10条消息的请求将返回您已经看到的消息的混合,还有一些新的-因此您永远不会真正知道何时看到它们。
队列可能不是在您的用例中使用的正确工具-但由于我不知道您的用例,因此很难说。
答案 3 :(得分:0)
我知道这有点死机,但我昨晚在尝试从 SQS 的死信队列中提取一些所有消息时来到这里。虽然接受的答案,“你不能保证从队列中获取所有消息”是绝对正确的,但我确实想为任何可能登陆这里并且需要绕过每个请求的 10
消息限制的人提供一个答案来自 AWS。
就我而言,我的项目中已经有一些依赖项,我过去常常使用它们来简化工作。
lodash
- 这是我们在代码中使用的东西,以帮助使事情发挥作用。我认为我没有在下面使用它,但我将它包含在文件中。cli-progress
- 这为您的 CLI 提供了一个不错的小进度条。在对与另一个系统集成的一些生产错误进行故障排除时,将以下内容放在一起。我们的 DLQ 消息包含我需要的一些标识符,以便制定云监视查询以进行故障排除。鉴于这是 AWS 中的两个不同 GUI,来回切换很麻烦,因为我们的 AWS 会话是通过一种联合形式进行的,并且会话最多只能持续一个小时。
#!/usr/bin/env node
const _ = require('lodash');
const aswSdk = require('aws-sdk');
const cliProgress = require('cli-progress');
const queueUrl = 'https://[put-your-url-here]';
const queueRegion = 'us-west-1';
const getMessages = async (sqs) => {
const resp = await sqs.receiveMessage({
QueueUrl: queueUrl,
MaxNumberOfMessages: 10,
}).promise();
return resp.Messages;
};
const main = async () => {
const sqs = new aswSdk.SQS({ region: queueRegion });
// First thing we need to do is get the current number of messages in the DLQ.
const attributes = await sqs.getQueueAttributes({
QueueUrl: queueUrl,
AttributeNames: ['All'], // Probably could thin this down but its late
}).promise();
const numberOfMessage = Number(attributes.Attributes.ApproximateNumberOfMessages);
// Next we create a in-memory cache for the messages
const allMessages = {};
let running = true;
// Honesty here: The examples we have in existing code use the multi-bar. It was about 10PM and I had 28 DLQ messages I was looking into. I didn't feel it was worth converting the multi-bar to a single-bar. Look into the docs on the github page if this is really a sticking point for you.
const progress = new cliProgress.MultiBar({
format: ' {bar} | {name} | {value}/{total}',
hideCursor: true,
clearOnComplete: true,
stopOnComplete: true
}, cliProgress.Presets.shades_grey);
const progressBar = progress.create(numberOfMessage, 0, { name: 'Messages' });
// TODO: put in a time limit to avoid an infinite loop.
// NOTE: For 28 messages I managed to get them all with this approach in about 15 seconds. When/if I cleanup this script I plan to add the time based short-circuit at that point.
while (running) {
// Fetch all the messages we can from the queue. The number of messages is not guaranteed per the AWS documentation.
let messages = await getMessages(sqs);
for (let i = 0; i < messages.length; i++) {
// Loop though the existing messages and only copy messages we have not already cached.
let message = messages[i];
let data = allMessages[message.MessageId];
if (data === undefined) {
allMessages[message.MessageId] = message;
}
}
// Update our progress bar with the current progress
const discoveredMessageCount = Object.keys(allMessages).length;
progressBar.update(discoveredMessageCount);
// Give a quick pause just to make sure we don't get rate limited or something
await new Promise((resolve) => setTimeout(resolve, 1000));
running = discoveredMessageCount !== numberOfMessage;
}
// Now that we have all the messages I printed them to console so I could copy/paste the output into LibreCalc (excel-like tool). I split on the semicolon for rows out of habit since sometimes similar scripts deal with data that has commas in it.
const keys = Object.keys(allMessages);
console.log('Message ID;ID');
for (let i = 0; i < keys.length; i++) {
const message = allMessages[keys[i]];
const decodedBody = JSON.parse(message.Body);
console.log(`${message.MessageId};${decodedBody.id}`);
}
};
main();