or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

batch-operations.mdclient-configuration.mddead-letter-queues.mdindex.mdmessage-move-tasks.mdmessage-operations.mdqueue-attributes-tags.mdqueue-management.mdqueue-permissions.md
tile.json

batch-operations.mddocs/

Batch Operations

High-performance batch operations for sending, deleting, and changing visibility of multiple messages in single API calls, reducing request overhead and improving throughput.

Capabilities

Send Message Batch

Sends multiple messages in a single request (up to 10 messages per batch).

class SendMessageBatchCommand {
  constructor(input: SendMessageBatchCommandInput);
}

interface SendMessageBatchCommandInput {
  /** URL of the target queue */
  QueueUrl: string;
  /** Array of messages to send (up to 10) */
  Entries: SendMessageBatchRequestEntry[];
}

interface SendMessageBatchRequestEntry {
  /** Unique identifier for this entry (within the batch) */
  Id: string;
  /** Message payload (up to 1 MB) */
  MessageBody: string;
  /** Delay before message becomes available (0-900 seconds) */
  DelaySeconds?: number;
  /** Custom message attributes */
  MessageAttributes?: Record<string, MessageAttributeValue>;
  /** Deduplication ID for FIFO queues */
  MessageDeduplicationId?: string;
  /** Group ID for FIFO queues */
  MessageGroupId?: string;
  /** System-defined message attributes */
  MessageSystemAttributes?: Record<MessageSystemAttributeNameForSends, MessageSystemAttributeValue>;
}

interface SendMessageBatchCommandOutput {
  /** Successfully sent messages */
  Successful: SendMessageBatchResultEntry[];
  /** Failed message entries */
  Failed: BatchResultErrorEntry[];
}

interface SendMessageBatchResultEntry {
  /** Entry ID from the request */
  Id: string;
  /** Unique message identifier */
  MessageId: string;
  /** MD5 hash of the message body */
  MD5OfBody: string;
  /** MD5 hash of message attributes */
  MD5OfMessageAttributes?: string;
  /** MD5 hash of system attributes */
  MD5OfMessageSystemAttributes?: string;
  /** FIFO sequence number */
  SequenceNumber?: string;
}

Usage Examples:

import { SQSClient, SendMessageBatchCommand } from "@aws-sdk/client-sqs";

const client = new SQSClient({ region: "us-east-1" });

// Send multiple messages in batch
const batchResult = await client.send(new SendMessageBatchCommand({
  QueueUrl: "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue",
  Entries: [
    {
      Id: "msg1",
      MessageBody: JSON.stringify({ orderId: "12345", status: "pending" })
    },
    {
      Id: "msg2", 
      MessageBody: JSON.stringify({ orderId: "12346", status: "processing" }),
      MessageAttributes: {
        Priority: {
          StringValue: "high",
          DataType: "String"
        }
      }
    },
    {
      Id: "msg3",
      MessageBody: JSON.stringify({ orderId: "12347", status: "completed" }),
      DelaySeconds: 60
    }
  ]
}));

// Process results
console.log(`Successfully sent ${batchResult.Successful.length} messages`);
for (const success of batchResult.Successful) {
  console.log(`Message ${success.Id} sent with ID: ${success.MessageId}`);
}

if (batchResult.Failed.length > 0) {
  console.log(`Failed to send ${batchResult.Failed.length} messages`);
  for (const failure of batchResult.Failed) {
    console.log(`Message ${failure.Id} failed: ${failure.Message}`);
  }
}

// Send FIFO batch
const fifoBatch = await client.send(new SendMessageBatchCommand({
  QueueUrl: "https://sqs.us-east-1.amazonaws.com/123456789012/MyFifoQueue.fifo",
  Entries: [
    {
      Id: "order1",
      MessageBody: "Order 1 data",
      MessageGroupId: "group1",
      MessageDeduplicationId: "dedup1"
    },
    {
      Id: "order2", 
      MessageBody: "Order 2 data",
      MessageGroupId: "group1",
      MessageDeduplicationId: "dedup2"
    }
  ]
}));

Delete Message Batch

Deletes multiple messages in a single request using their receipt handles.

class DeleteMessageBatchCommand {
  constructor(input: DeleteMessageBatchCommandInput);
}

interface DeleteMessageBatchCommandInput {
  /** URL of the queue containing the messages */
  QueueUrl: string;
  /** Array of messages to delete (up to 10) */
  Entries: DeleteMessageBatchRequestEntry[];
}

interface DeleteMessageBatchRequestEntry {
  /** Unique identifier for this entry (within the batch) */
  Id: string;
  /** Receipt handle of the message to delete */
  ReceiptHandle: string;
}

interface DeleteMessageBatchCommandOutput {
  /** Successfully deleted messages */
  Successful: DeleteMessageBatchResultEntry[];
  /** Failed delete entries */
  Failed: BatchResultErrorEntry[];
}

interface DeleteMessageBatchResultEntry {
  /** Entry ID from the request */
  Id: string;
}

Usage Examples:

// Receive messages for batch processing
const received = await client.send(new ReceiveMessageCommand({
  QueueUrl: "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue",
  MaxNumberOfMessages: 10
}));

const deleteEntries: DeleteMessageBatchRequestEntry[] = [];
const messages = received.Messages || [];

// Process each message
for (let i = 0; i < messages.length; i++) {
  const message = messages[i];
  
  try {
    // Process message
    await processMessage(message.Body);
    
    // Add to delete batch
    deleteEntries.push({
      Id: `delete_${i}`,
      ReceiptHandle: message.ReceiptHandle!
    });
    
  } catch (error) {
    console.error(`Failed to process message ${message.MessageId}:`, error);
  }
}

// Delete successfully processed messages in batch
if (deleteEntries.length > 0) {
  const deleteResult = await client.send(new DeleteMessageBatchCommand({
    QueueUrl: "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue",
    Entries: deleteEntries
  }));
  
  console.log(`Successfully deleted ${deleteResult.Successful.length} messages`);
  
  // Handle failed deletes
  for (const failure of deleteResult.Failed) {
    console.log(`Failed to delete message ${failure.Id}: ${failure.Message}`);
  }
}

async function processMessage(body: string | undefined) {
  if (!body) return;
  const data = JSON.parse(body);
  // Process the message
  console.log("Processing:", data);
}

Change Message Visibility Batch

Changes visibility timeout for multiple messages in a single request.

class ChangeMessageVisibilityBatchCommand {
  constructor(input: ChangeMessageVisibilityBatchCommandInput);
}

interface ChangeMessageVisibilityBatchCommandInput {
  /** URL of the queue containing the messages */
  QueueUrl: string;
  /** Array of visibility changes (up to 10) */
  Entries: ChangeMessageVisibilityBatchRequestEntry[];
}

interface ChangeMessageVisibilityBatchRequestEntry {
  /** Unique identifier for this entry (within the batch) */
  Id: string;
  /** Receipt handle of the message */
  ReceiptHandle: string;
  /** New visibility timeout in seconds (0-43200) */
  VisibilityTimeoutSeconds?: number;
}

interface ChangeMessageVisibilityBatchCommandOutput {
  /** Successfully updated messages */
  Successful: ChangeMessageVisibilityBatchResultEntry[];
  /** Failed update entries */
  Failed: BatchResultErrorEntry[];
}

interface ChangeMessageVisibilityBatchResultEntry {
  /** Entry ID from the request */
  Id: string;
}

Usage Examples:

// Receive messages for long processing
const received = await client.send(new ReceiveMessageCommand({
  QueueUrl: "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue",
  MaxNumberOfMessages: 10
}));

// Extend visibility for all messages that need longer processing
const visibilityEntries: ChangeMessageVisibilityBatchRequestEntry[] = [];

for (let i = 0; i < (received.Messages?.length || 0); i++) {
  const message = received.Messages![i];
  
  // Check if message needs extended processing time
  if (requiresLongProcessing(message.Body)) {
    visibilityEntries.push({
      Id: `extend_${i}`,
      ReceiptHandle: message.ReceiptHandle!,
      VisibilityTimeoutSeconds: 600 // 10 minutes
    });
  }
}

// Apply visibility changes in batch
if (visibilityEntries.length > 0) {
  const visibilityResult = await client.send(new ChangeMessageVisibilityBatchCommand({
    QueueUrl: "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue",
    Entries: visibilityEntries
  }));
  
  console.log(`Extended visibility for ${visibilityResult.Successful.length} messages`);
}

function requiresLongProcessing(body: string | undefined): boolean {
  if (!body) return false;
  try {
    const data = JSON.parse(body);
    return data.processingType === 'long-running';
  } catch {
    return false;
  }
}

Batch Error Handling

interface BatchResultErrorEntry {
  /** Entry ID from the request */
  Id: string;
  /** Whether the error is sender's fault */
  SenderFault: boolean;
  /** Error code */
  Code: string;
  /** Error message */
  Message?: string;
}

Common batch operation errors:

  • BatchEntryIdsNotDistinct: Batch contains duplicate entry IDs
  • EmptyBatchRequest: Batch request contains no entries
  • TooManyEntriesInBatchRequest: Batch contains more than 10 entries
  • InvalidBatchEntryId: Entry ID format is invalid
  • ReceiptHandleIsInvalid: One or more receipt handles are invalid

Usage Examples:

// Robust batch processing with error handling
async function sendMessagesBatch(queueUrl: string, messages: Array<{id: string, body: string}>) {
  // Split into chunks of 10 (SQS batch limit)
  const chunks = [];
  for (let i = 0; i < messages.length; i += 10) {
    chunks.push(messages.slice(i, i + 10));
  }
  
  const results = {
    successful: [] as string[],
    failed: [] as Array<{id: string, error: string}>
  };
  
  for (const chunk of chunks) {
    try {
      const batchResult = await client.send(new SendMessageBatchCommand({
        QueueUrl: queueUrl,
        Entries: chunk.map(msg => ({
          Id: msg.id,
          MessageBody: msg.body
        }))
      }));
      
      // Collect successful sends
      results.successful.push(...batchResult.Successful.map(s => s.Id));
      
      // Collect failed sends for retry
      for (const failure of batchResult.Failed) {
        results.failed.push({
          id: failure.Id,
          error: failure.Message || 'Unknown error'
        });
      }
      
    } catch (error) {
      // Handle batch-level errors
      console.error("Batch send failed:", error);
      results.failed.push(...chunk.map(msg => ({
        id: msg.id,
        error: error.message || 'Batch operation failed'
      })));
    }
  }
  
  return results;
}

// Usage
const messages = [
  { id: "msg1", body: "Message 1" },
  { id: "msg2", body: "Message 2" },
  // ... up to any number of messages (will be batched automatically)
];

const result = await sendMessagesBatch(queueUrl, messages);
console.log(`Sent ${result.successful.length} messages, ${result.failed.length} failed`);

Best Practices

Batch Size Optimization

// Optimal batch sizes for different operations
const BATCH_SIZE = 10; // Maximum allowed by SQS

// For high-throughput scenarios, always use full batches
const messagesToSend = largeMessageArray;
const batches = [];

for (let i = 0; i < messagesToSend.length; i += BATCH_SIZE) {
  batches.push(messagesToSend.slice(i, i + BATCH_SIZE));
}

for (const batch of batches) {
  await client.send(new SendMessageBatchCommand({
    QueueUrl: queueUrl,
    Entries: batch.map((msg, index) => ({
      Id: `batch_${Date.now()}_${index}`,
      MessageBody: msg
    }))
  }));
}

Error Recovery

// Implement exponential backoff for failed batch entries
async function sendWithRetry(entries: SendMessageBatchRequestEntry[], queueUrl: string, maxRetries = 3) {
  let remainingEntries = [...entries];
  let attempt = 0;
  
  while (remainingEntries.length > 0 && attempt < maxRetries) {
    const result = await client.send(new SendMessageBatchCommand({
      QueueUrl: queueUrl,
      Entries: remainingEntries
    }));
    
    // Remove successful entries
    const failedIds = new Set(result.Failed.map(f => f.Id));
    remainingEntries = remainingEntries.filter(entry => failedIds.has(entry.Id));
    
    if (remainingEntries.length > 0) {
      attempt++;
      // Exponential backoff
      await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
    }
  }
  
  return remainingEntries; // Any remaining failed entries
}