You don't have to block the queue, but rather only add messages when they are good to be processed. If you have a flow in which certain steps (messages to be processed) depend on the success of previous steps, you should make these messages only be added after the previous step (message) succeeds.
Let's say you have an SQS queue with a handler to process the message, it could look something like below.
Since you're using the same FIFO queue for all steps, I'm using the STEP as the MessageGroupId
to allow messages of different steps to be processed in parallel (as they could belong to different orders), but the steps of one particular order are always processed in sequence and require the previous one to succeed.
On a side note, you shouldn't need FIFO queues with the approach below, and you could have separate queues with separate handlers for each step.
const sqs = new AWS.SQS();
const STEPS = {
ORDER_PAID: "ORDER_PAID",
ORDER_APPROVED: "ORDER_APPROVED",
ORDER_COMPLETED: "ORDER_COMPLETED",
};
async function sendMessage(step: string, orderId: string) {
return sqs
.sendMessage({
QueueUrl: process.env.YOUR_QUEUE_URL || "",
MessageGroupId: step,
MessageBody: JSON.stringify({
currentStep: step,
orderId,
}),
})
.promise();
}
exports.handler = async function (event: any, context: any) {
for (const message of event.Records) {
const { currentStep, orderId } = JSON.parse(message.body);
if (currentStep === STEPS.ORDER_PAID) {
// process order paid, then add next step back to queue
await sendMessage(STEPS.ORDER_APPROVED, orderId);
}
if (currentStep === STEPS.ORDER_APPROVED) {
// process order approved, then add next step back to queue
await sendMessage(STEPS.ORDER_COMPLETED, orderId);
}
if (currentStep === STEPS.ORDER_COMPLETED) {
// process order completed
}
}
return context.logStreamName;
};