Initial commit
This commit is contained in:
310
skills/aws-sdk-java-v2-messaging/SKILL.md
Normal file
310
skills/aws-sdk-java-v2-messaging/SKILL.md
Normal file
@@ -0,0 +1,310 @@
|
||||
---
|
||||
name: aws-sdk-java-v2-messaging
|
||||
description: Implement AWS messaging patterns using AWS SDK for Java 2.x for SQS queues and SNS topics. Send/receive messages, manage FIFO queues, implement DLQ, publish messages, manage subscriptions, and build pub/sub patterns.
|
||||
category: aws
|
||||
tags: [aws, sqs, sns, java, sdk, messaging, pub-sub, queues, events]
|
||||
version: 1.1.0
|
||||
allowed-tools: Read, Write, Bash, Grep
|
||||
---
|
||||
|
||||
# AWS SDK for Java 2.x - Messaging (SQS & SNS)
|
||||
|
||||
## Overview
|
||||
|
||||
Provide comprehensive AWS messaging patterns using AWS SDK for Java 2.x for both SQS and SNS services. Include client setup, queue management, message operations, subscription management, and Spring Boot integration patterns.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when working with:
|
||||
- Amazon SQS queues for message queuing
|
||||
- SNS topics for event publishing and notification
|
||||
- FIFO queues and standard queues
|
||||
- Dead Letter Queues (DLQ) for message handling
|
||||
- SNS subscriptions with email, SMS, SQS, Lambda endpoints
|
||||
- Pub/sub messaging patterns and event-driven architectures
|
||||
- Spring Boot integration with AWS messaging services
|
||||
- Testing strategies using LocalStack or Testcontainers
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Dependencies
|
||||
|
||||
```xml
|
||||
<!-- SQS -->
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>sqs</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SNS -->
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>sns</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Basic Client Setup
|
||||
|
||||
```java
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.sqs.SqsClient;
|
||||
import software.amazon.awssdk.services.sns.SnsClient;
|
||||
|
||||
SqsClient sqsClient = SqsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
|
||||
SnsClient snsClient = SnsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic SQS Operations
|
||||
|
||||
#### Create and Send Message
|
||||
```java
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.sqs.SqsClient;
|
||||
import software.amazon.awssdk.services.sqs.model.*;
|
||||
|
||||
// Setup SQS client
|
||||
SqsClient sqsClient = SqsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
|
||||
// Create queue
|
||||
String queueUrl = sqsClient.createQueue(CreateQueueRequest.builder()
|
||||
.queueName("my-queue")
|
||||
.build()).queueUrl();
|
||||
|
||||
// Send message
|
||||
String messageId = sqsClient.sendMessage(SendMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.messageBody("Hello, SQS!")
|
||||
.build()).messageId();
|
||||
```
|
||||
|
||||
#### Receive and Delete Message
|
||||
```java
|
||||
// Receive messages with long polling
|
||||
ReceiveMessageResponse response = sqsClient.receiveMessage(ReceiveMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.maxNumberOfMessages(10)
|
||||
.waitTimeSeconds(20)
|
||||
.build());
|
||||
|
||||
// Process and delete messages
|
||||
response.messages().forEach(message -> {
|
||||
System.out.println("Received: " + message.body());
|
||||
sqsClient.deleteMessage(DeleteMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.receiptHandle(message.receiptHandle())
|
||||
.build());
|
||||
});
|
||||
```
|
||||
|
||||
### Basic SNS Operations
|
||||
|
||||
#### Create Topic and Publish
|
||||
```java
|
||||
import software.amazon.awssdk.services.sns.SnsClient;
|
||||
import software.amazon.awssdk.services.sns.model.*;
|
||||
|
||||
// Setup SNS client
|
||||
SnsClient snsClient = SnsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
|
||||
// Create topic
|
||||
String topicArn = snsClient.createTopic(CreateTopicRequest.builder()
|
||||
.name("my-topic")
|
||||
.build()).topicArn();
|
||||
|
||||
// Publish message
|
||||
String messageId = snsClient.publish(PublishRequest.builder()
|
||||
.topicArn(topicArn)
|
||||
.subject("Test Notification")
|
||||
.message("Hello, SNS!")
|
||||
.build()).messageId();
|
||||
```
|
||||
|
||||
### Advanced Examples
|
||||
|
||||
#### FIFO Queue Pattern
|
||||
```java
|
||||
// Create FIFO queue
|
||||
Map<QueueAttributeName, String> attributes = Map.of(
|
||||
QueueAttributeName.FIFO_QUEUE, "true",
|
||||
QueueAttributeName.CONTENT_BASED_DEDUPLICATION, "true"
|
||||
);
|
||||
|
||||
String fifoQueueUrl = sqsClient.createQueue(CreateQueueRequest.builder()
|
||||
.queueName("my-queue.fifo")
|
||||
.attributes(attributes)
|
||||
.build()).queueUrl();
|
||||
|
||||
// Send FIFO message with group ID
|
||||
String fifoMessageId = sqsClient.sendMessage(SendMessageRequest.builder()
|
||||
.queueUrl(fifoQueueUrl)
|
||||
.messageBody("Order #12345")
|
||||
.messageGroupId("orders")
|
||||
.messageDeduplicationId(UUID.randomUUID().toString())
|
||||
.build()).messageId();
|
||||
```
|
||||
|
||||
#### SNS to SQS Subscription
|
||||
```java
|
||||
// Create SQS queue for subscription
|
||||
String subscriptionQueueUrl = sqsClient.createQueue(CreateQueueRequest.builder()
|
||||
.queueName("notification-subscriber")
|
||||
.build()).queueUrl();
|
||||
|
||||
// Get queue ARN
|
||||
String queueArn = sqsClient.getQueueAttributes(GetQueueAttributesRequest.builder()
|
||||
.queueUrl(subscriptionQueueUrl)
|
||||
.attributeNames(QueueAttributeName.QUEUE_ARN)
|
||||
.build()).attributes().get(QueueAttributeName.QUEUE_ARN);
|
||||
|
||||
// Subscribe SQS to SNS
|
||||
String subscriptionArn = snsClient.subscribe(SubscribeRequest.builder()
|
||||
.protocol("sqs")
|
||||
.endpoint(queueArn)
|
||||
.topicArn(topicArn)
|
||||
.build()).subscriptionArn();
|
||||
```
|
||||
|
||||
### Spring Boot Integration Example
|
||||
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class OrderNotificationService {
|
||||
|
||||
private final SnsClient snsClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Value("${aws.sns.order-topic-arn}")
|
||||
private String orderTopicArn;
|
||||
|
||||
public void sendOrderNotification(Order order) {
|
||||
try {
|
||||
String jsonMessage = objectMapper.writeValueAsString(order);
|
||||
|
||||
snsClient.publish(PublishRequest.builder()
|
||||
.topicArn(orderTopicArn)
|
||||
.subject("New Order Received")
|
||||
.message(jsonMessage)
|
||||
.messageAttributes(Map.of(
|
||||
"orderType", MessageAttributeValue.builder()
|
||||
.dataType("String")
|
||||
.stringValue(order.getType())
|
||||
.build()))
|
||||
.build());
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to send order notification", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### SQS Best Practices
|
||||
- **Use long polling**: Set `waitTimeSeconds` (20-40 seconds) to reduce empty responses
|
||||
- **Batch operations**: Use `sendMessageBatch` for multiple messages to reduce API calls
|
||||
- **Visibility timeout**: Set appropriately based on message processing time (default 30 seconds)
|
||||
- **Delete messages**: Always delete messages after successful processing
|
||||
- **Handle duplicates**: Implement idempotent processing for retries
|
||||
- **Implement DLQ**: Route failed messages to dead letter queues for analysis
|
||||
- **Monitor queue depth**: Use CloudWatch alarms for high queue backlog
|
||||
- **Use FIFO queues**: When message order and deduplication are critical
|
||||
|
||||
### SNS Best Practices
|
||||
- **Use filter policies**: Reduce noise by filtering messages at the source
|
||||
- **Message attributes**: Add metadata for subscription routing decisions
|
||||
- **Retry logic**: Handle transient failures with exponential backoff
|
||||
- **Monitor failed deliveries**: Set up CloudWatch alarms for failed notifications
|
||||
- **Security**: Use IAM policies for access control and data encryption
|
||||
- **FIFO topics**: Use when order and deduplication are critical
|
||||
- **Avoid large payloads**: Keep messages under 256KB for optimal performance
|
||||
|
||||
### General Guidelines
|
||||
- **Region consistency**: Use the same region for all AWS resources
|
||||
- **Resource naming**: Use consistent naming conventions for queues and topics
|
||||
- **Error handling**: Implement proper exception handling and logging
|
||||
- **Testing**: Use LocalStack for local development and testing
|
||||
- **Documentation**: Document subscription endpoints and message formats
|
||||
|
||||
## Instructions
|
||||
|
||||
### Setup AWS Credentials
|
||||
Configure AWS credentials using environment variables, AWS CLI, or IAM roles:
|
||||
```bash
|
||||
export AWS_ACCESS_KEY_ID=your-access-key
|
||||
export AWS_SECRET_ACCESS_KEY=your-secret-key
|
||||
export AWS_REGION=us-east-1
|
||||
```
|
||||
|
||||
### Configure Clients
|
||||
```java
|
||||
// Basic client configuration
|
||||
SqsClient sqsClient = SqsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
|
||||
// Advanced client with custom configuration
|
||||
SnsClient snsClient = SnsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.credentialsProvider(DefaultCredentialsProvider.create())
|
||||
.httpClient(UrlConnectionHttpClient.create())
|
||||
.build();
|
||||
```
|
||||
|
||||
### Implement Message Processing
|
||||
1. **Connect** to SQS/SNS using the AWS SDK clients
|
||||
2. **Create** queues and topics as needed
|
||||
3. **Send/receive** messages with appropriate timeout settings
|
||||
4. **Process** messages in batches for efficiency
|
||||
5. **Delete** messages after successful processing
|
||||
6. **Handle** failures with proper error handling and retries
|
||||
|
||||
### Integrate with Spring Boot
|
||||
1. **Configure** beans for `SqsClient` and `SnsClient` in `@Configuration` classes
|
||||
2. **Use** `@Value` to inject queue URLs and topic ARNs from properties
|
||||
3. **Create** service classes with business logic for messaging operations
|
||||
4. **Implement** error handling with `@Retryable` or custom retry logic
|
||||
5. **Test** integration using Testcontainers or LocalStack
|
||||
|
||||
### Monitor and Debug
|
||||
- Use AWS CloudWatch for monitoring queue depth and message metrics
|
||||
- Enable AWS SDK logging for debugging client operations
|
||||
- Implement proper logging for message processing activities
|
||||
- Use AWS X-Ray for distributed tracing in production environments
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
- **Queue does not exist**: Verify queue URL and permissions
|
||||
- **Message not received**: Check visibility timeout and consumer logic
|
||||
- **Permission denied**: Verify IAM policies and credentials
|
||||
- **Connection timeout**: Check network connectivity and region configuration
|
||||
- **Rate limiting**: Implement retry logic with exponential backoff
|
||||
|
||||
### Performance Optimization
|
||||
- Use long polling to reduce empty responses
|
||||
- Batch message operations to minimize API calls
|
||||
- Adjust visibility timeout based on processing time
|
||||
- Implement connection pooling and reuse clients
|
||||
- Use appropriate message sizes to avoid fragmentation
|
||||
|
||||
## Detailed References
|
||||
|
||||
For comprehensive API documentation and advanced patterns, see:
|
||||
|
||||
- [@references/detailed-sqs-operations] - Complete SQS operations reference
|
||||
- [@references/detailed-sns-operations] - Complete SNS operations reference
|
||||
- [@references/spring-boot-integration] - Spring Boot integration patterns
|
||||
- [@references/aws-official-documentation] - Official AWS documentation and best practices
|
||||
@@ -0,0 +1,158 @@
|
||||
# AWS SQS & SNS Official Documentation Reference
|
||||
|
||||
This file contains reference information extracted from official AWS resources for the AWS SDK for Java 2.x messaging patterns.
|
||||
|
||||
## Source Documents
|
||||
- [AWS Java SDK v2 Examples - SQS](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/sqs)
|
||||
- [AWS Java SDK v2 Examples - SNS](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/sns)
|
||||
- [AWS SQS Developer Guide](https://docs.aws.amazon.com/sqs/latest/dg/)
|
||||
- [AWS SNS Developer Guide](https://docs.aws.amazon.com/sns/latest/dg/)
|
||||
|
||||
## Amazon SQS Reference
|
||||
|
||||
### Core Operations
|
||||
- **CreateQueue** - Create new SQS queue
|
||||
- **DeleteMessage** - Delete individual message from queue
|
||||
- **ListQueues** - List available queues
|
||||
- **ReceiveMessage** - Receive messages from queue
|
||||
- **SendMessage** - Send message to queue
|
||||
- **SendMessageBatch** - Send multiple messages to queue
|
||||
|
||||
### Advanced Features
|
||||
- **Large Message Handling** - Use S3 for messages larger than 256KB
|
||||
- **Batch Operations** - Process multiple messages efficiently
|
||||
- **Long Polling** - Reduce empty responses with `waitTimeSeconds`
|
||||
- **Visibility Timeout** - Control message visibility during processing
|
||||
- **Dead Letter Queues (DLQ)** - Handle failed messages
|
||||
- **FIFO Queues** - Ensure message ordering and deduplication
|
||||
|
||||
### Java SDK v2 Key Classes
|
||||
```java
|
||||
// Core clients and models
|
||||
software.amazon.awssdk.services.sqs.SqsClient
|
||||
software.amazon.awssdk.services.sqs.model.*
|
||||
software.amazon.awssdk.services.sqs.model.QueueAttributeName
|
||||
```
|
||||
|
||||
## Amazon SNS Reference
|
||||
|
||||
### Core Operations
|
||||
- **CreateTopic** - Create new SNS topic
|
||||
- **Publish** - Send message to topic
|
||||
- **Subscribe** - Subscribe endpoint to topic
|
||||
- **ListSubscriptions** - List topic subscriptions
|
||||
- **Unsubscribe** - Remove subscription
|
||||
|
||||
### Advanced Features
|
||||
- **Platform Endpoints** - Mobile push notifications
|
||||
- **SMS Publishing** - Send SMS messages
|
||||
- **FIFO Topics** - Ordered message delivery with deduplication
|
||||
- **Filter Policies** - Filter messages based on attributes
|
||||
- **Message Attributes** - Enrich messages with metadata
|
||||
- **DLQ for Subscriptions** - Handle failed deliveries
|
||||
|
||||
### Java SDK v2 Key Classes
|
||||
```java
|
||||
// Core clients and models
|
||||
software.amazon.awssdk.services.sns.SnsClient
|
||||
software.amazon.awssdk.services.sns.model.*
|
||||
software.amazon.awssdk.services.sns.model.MessageAttributeValue
|
||||
```
|
||||
|
||||
## Best Practices from AWS
|
||||
|
||||
### SQS Best Practices
|
||||
1. **Use Long Polling**: Set `waitTimeSeconds` (10-40 seconds) to reduce empty responses
|
||||
2. **Batch Operations**: Use `SendMessageBatch` for efficiency
|
||||
3. **Visibility Timeout**: Set appropriately based on processing time
|
||||
4. **Handle Duplicates**: Implement idempotent processing for retries
|
||||
5. **Monitor Queue Depth**: Use CloudWatch for monitoring
|
||||
6. **Implement DLQ**: Route failed messages for analysis
|
||||
|
||||
### SNS Best Practices
|
||||
1. **Use Filter Policies**: Reduce noise by filtering messages
|
||||
2. **Message Attributes**: Add metadata for routing decisions
|
||||
3. **Retry Logic**: Handle transient failures gracefully
|
||||
4. **Monitor Failed Deliveries**: Set up CloudWatch alarms
|
||||
5. **Security**: Use IAM policies for access control
|
||||
6. **FIFO Topics**: Use when order and deduplication are critical
|
||||
|
||||
## Error Handling Patterns
|
||||
|
||||
### Common SQS Errors
|
||||
- **QueueDoesNotExistException**: Verify queue URL
|
||||
- **MessageNotInflightException**: Check message visibility
|
||||
- **OverLimitException**: Implement backoff/retry logic
|
||||
- **InvalidAttributeValueException**: Validate queue attributes
|
||||
|
||||
### Common SNS Errors
|
||||
- **NotFoundException**: Verify topic ARN
|
||||
- **InvalidParameterException**: Validate subscription parameters
|
||||
- **InternalFailureException**: Implement retry logic
|
||||
- **AuthorizationErrorException**: Check IAM permissions
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
### Spring Boot Integration
|
||||
- Use `@Service` classes for business logic
|
||||
- Inject `SqsClient` and `SnsClient` via constructor injection
|
||||
- Configure clients with `@Configuration` beans
|
||||
- Use `@Value` for externalizing configuration
|
||||
|
||||
### Testing Strategies
|
||||
- Use LocalStack for local development
|
||||
- Mock AWS services with Mockito for unit tests
|
||||
- Integrate with Testcontainers for integration tests
|
||||
- Test idempotent operations thoroughly
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### SQS Configuration
|
||||
```java
|
||||
SqsClient sqsClient = SqsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
```
|
||||
|
||||
### SNS Configuration
|
||||
```java
|
||||
SnsClient snsClient = SnsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
```
|
||||
|
||||
### Advanced Configuration
|
||||
- Override endpoint for local development
|
||||
- Configure custom credentials provider
|
||||
- Set custom HTTP client
|
||||
- Configure retry policies
|
||||
|
||||
## Monitoring and Observability
|
||||
|
||||
### SQS Metrics
|
||||
- ApproximateNumberOfMessagesVisible
|
||||
- ApproximateNumberOfMessagesNotVisible
|
||||
- ApproximateNumberOfMessagesDelayed
|
||||
- SentMessages
|
||||
- ReceiveCalls
|
||||
|
||||
### SNS Metrics
|
||||
- NumberOfNotifications
|
||||
- PublishSuccess
|
||||
- PublishFailed
|
||||
- SubscriptionConfirmation
|
||||
- SubscriptionConfirmationFailed
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### IAM Permissions
|
||||
- Grant least privilege access
|
||||
- Use IAM roles for EC2/ECS
|
||||
- Implement resource-based policies
|
||||
- Use condition keys for fine-grained control
|
||||
|
||||
### Data Protection
|
||||
- Encrypt sensitive data in messages
|
||||
- Use KMS for message encryption
|
||||
- Implement message signing
|
||||
- Secure endpoints with HTTPS
|
||||
@@ -0,0 +1,179 @@
|
||||
# Detailed SNS Operations Reference
|
||||
|
||||
## Topic Management
|
||||
|
||||
### Create Standard Topic
|
||||
```java
|
||||
public String createTopic(SnsClient snsClient, String topicName) {
|
||||
CreateTopicRequest request = CreateTopicRequest.builder()
|
||||
.name(topicName)
|
||||
.build();
|
||||
|
||||
CreateTopicResponse response = snsClient.createTopic(request);
|
||||
return response.topicArn();
|
||||
}
|
||||
```
|
||||
|
||||
### Create FIFO Topic
|
||||
```java
|
||||
public String createFifoTopic(SnsClient snsClient, String topicName) {
|
||||
Map<String, String> attributes = new HashMap<>();
|
||||
attributes.put("FifoTopic", "true");
|
||||
attributes.put("ContentBasedDeduplication", "true");
|
||||
|
||||
CreateTopicRequest request = CreateTopicRequest.builder()
|
||||
.name(topicName + ".fifo")
|
||||
.attributes(attributes)
|
||||
.build();
|
||||
|
||||
CreateTopicResponse response = snsClient.createTopic(request);
|
||||
return response.topicArn();
|
||||
}
|
||||
```
|
||||
|
||||
### Topic Operations
|
||||
```java
|
||||
public List<Topic> listTopics(SnsClient snsClient) {
|
||||
return snsClient.listTopics().topics();
|
||||
}
|
||||
|
||||
public String getTopicArn(SnsClient snsClient, String topicName) {
|
||||
return snsClient.createTopic(CreateTopicRequest.builder()
|
||||
.name(topicName)
|
||||
.build()).topicArn();
|
||||
}
|
||||
```
|
||||
|
||||
## Message Publishing
|
||||
|
||||
### Publish Basic Message
|
||||
```java
|
||||
public String publishMessage(SnsClient snsClient, String topicArn, String message) {
|
||||
PublishRequest request = PublishRequest.builder()
|
||||
.topicArn(topicArn)
|
||||
.message(message)
|
||||
.build();
|
||||
|
||||
PublishResponse response = snsClient.publish(request);
|
||||
return response.messageId();
|
||||
}
|
||||
```
|
||||
|
||||
### Publish with Subject
|
||||
```java
|
||||
public String publishMessageWithSubject(SnsClient snsClient,
|
||||
String topicArn,
|
||||
String subject,
|
||||
String message) {
|
||||
PublishRequest request = PublishRequest.builder()
|
||||
.topicArn(topicArn)
|
||||
.subject(subject)
|
||||
.message(message)
|
||||
.build();
|
||||
|
||||
PublishResponse response = snsClient.publish(request);
|
||||
return response.messageId();
|
||||
}
|
||||
```
|
||||
|
||||
### Publish with Attributes
|
||||
```java
|
||||
public String publishMessageWithAttributes(SnsClient snsClient,
|
||||
String topicArn,
|
||||
String message,
|
||||
Map<String, String> attributes) {
|
||||
Map<String, MessageAttributeValue> messageAttributes = attributes.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
e -> MessageAttributeValue.builder()
|
||||
.dataType("String")
|
||||
.stringValue(e.getValue())
|
||||
.build()));
|
||||
|
||||
PublishRequest request = PublishRequest.builder()
|
||||
.topicArn(topicArn)
|
||||
.message(message)
|
||||
.messageAttributes(messageAttributes)
|
||||
.build();
|
||||
|
||||
PublishResponse response = snsClient.publish(request);
|
||||
return response.messageId();
|
||||
}
|
||||
```
|
||||
|
||||
### Publish FIFO Message
|
||||
```java
|
||||
public String publishFifoMessage(SnsClient snsClient,
|
||||
String topicArn,
|
||||
String message,
|
||||
String messageGroupId) {
|
||||
PublishRequest request = PublishRequest.builder()
|
||||
.topicArn(topicArn)
|
||||
.message(message)
|
||||
.messageGroupId(messageGroupId)
|
||||
.messageDeduplicationId(UUID.randomUUID().toString())
|
||||
.build();
|
||||
|
||||
PublishResponse response = snsClient.publish(request);
|
||||
return response.messageId();
|
||||
}
|
||||
```
|
||||
|
||||
## Subscription Management
|
||||
|
||||
### Subscribe Email to Topic
|
||||
```java
|
||||
public String subscribeEmail(SnsClient snsClient, String topicArn, String email) {
|
||||
SubscribeRequest request = SubscribeRequest.builder()
|
||||
.protocol("email")
|
||||
.endpoint(email)
|
||||
.topicArn(topicArn)
|
||||
.build();
|
||||
|
||||
SubscribeResponse response = snsClient.subscribe(request);
|
||||
return response.subscriptionArn();
|
||||
}
|
||||
```
|
||||
|
||||
### Subscribe SQS to Topic
|
||||
```java
|
||||
public String subscribeSqs(SnsClient snsClient, String topicArn, String queueArn) {
|
||||
SubscribeRequest request = SubscribeRequest.builder()
|
||||
.protocol("sqs")
|
||||
.endpoint(queueArn)
|
||||
.topicArn(topicArn)
|
||||
.build();
|
||||
|
||||
SubscribeResponse response = snsClient.subscribe(request);
|
||||
return response.subscriptionArn();
|
||||
}
|
||||
```
|
||||
|
||||
### Subscribe Lambda to Topic
|
||||
```java
|
||||
public String subscribeLambda(SnsClient snsClient, String topicArn, String lambdaArn) {
|
||||
SubscribeRequest request = SubscribeRequest.builder()
|
||||
.protocol("lambda")
|
||||
.endpoint(lambdaArn)
|
||||
.topicArn(topicArn)
|
||||
.build();
|
||||
|
||||
SubscribeResponse response = snsClient.subscribe(request);
|
||||
return response.subscriptionArn();
|
||||
}
|
||||
```
|
||||
|
||||
### Subscription Operations
|
||||
```java
|
||||
public List<Subscription> listSubscriptions(SnsClient snsClient, String topicArn) {
|
||||
return snsClient.listSubscriptionsByTopic(ListSubscriptionsByTopicRequest.builder()
|
||||
.topicArn(topicArn)
|
||||
.build()).subscriptions();
|
||||
}
|
||||
|
||||
public void unsubscribe(SnsClient snsClient, String subscriptionArn) {
|
||||
snsClient.unsubscribe(UnsubscribeRequest.builder()
|
||||
.subscriptionArn(subscriptionArn)
|
||||
.build());
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,199 @@
|
||||
# Detailed SQS Operations Reference
|
||||
|
||||
## Queue Management
|
||||
|
||||
### Create Standard Queue
|
||||
```java
|
||||
public String createQueue(SqsClient sqsClient, String queueName) {
|
||||
CreateQueueRequest request = CreateQueueRequest.builder()
|
||||
.queueName(queueName)
|
||||
.build();
|
||||
|
||||
CreateQueueResponse response = sqsClient.createQueue(request);
|
||||
return response.queueUrl();
|
||||
}
|
||||
```
|
||||
|
||||
### Create FIFO Queue
|
||||
```java
|
||||
public String createFifoQueue(SqsClient sqsClient, String queueName) {
|
||||
Map<QueueAttributeName, String> attributes = new HashMap<>();
|
||||
attributes.put(QueueAttributeName.FIFO_QUEUE, "true");
|
||||
attributes.put(QueueAttributeName.CONTENT_BASED_DEDUPLICATION, "true");
|
||||
|
||||
CreateQueueRequest request = CreateQueueRequest.builder()
|
||||
.queueName(queueName + ".fifo")
|
||||
.attributes(attributes)
|
||||
.build();
|
||||
|
||||
CreateQueueResponse response = sqsClient.createQueue(request);
|
||||
return response.queueUrl();
|
||||
}
|
||||
```
|
||||
|
||||
### Queue Operations
|
||||
```java
|
||||
public String getQueueUrl(SqsClient sqsClient, String queueName) {
|
||||
return sqsClient.getQueueUrl(GetQueueUrlRequest.builder()
|
||||
.queueName(queueName)
|
||||
.build()).queueUrl();
|
||||
}
|
||||
|
||||
public List<String> listQueues(SqsClient sqsClient) {
|
||||
return sqsClient.listQueues().queueUrls();
|
||||
}
|
||||
|
||||
public void purgeQueue(SqsClient sqsClient, String queueUrl) {
|
||||
sqsClient.purgeQueue(PurgeQueueRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.build());
|
||||
}
|
||||
```
|
||||
|
||||
## Message Operations
|
||||
|
||||
### Send Basic Message
|
||||
```java
|
||||
public String sendMessage(SqsClient sqsClient, String queueUrl, String messageBody) {
|
||||
SendMessageRequest request = SendMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.messageBody(messageBody)
|
||||
.build();
|
||||
|
||||
SendMessageResponse response = sqsClient.sendMessage(request);
|
||||
return response.messageId();
|
||||
}
|
||||
```
|
||||
|
||||
### Send Message with Attributes
|
||||
```java
|
||||
public String sendMessageWithAttributes(SqsClient sqsClient,
|
||||
String queueUrl,
|
||||
String messageBody,
|
||||
Map<String, String> attributes) {
|
||||
Map<String, MessageAttributeValue> messageAttributes = attributes.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
e -> MessageAttributeValue.builder()
|
||||
.dataType("String")
|
||||
.stringValue(e.getValue())
|
||||
.build()));
|
||||
|
||||
SendMessageRequest request = SendMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.messageBody(messageBody)
|
||||
.messageAttributes(messageAttributes)
|
||||
.build();
|
||||
|
||||
SendMessageResponse response = sqsClient.sendMessage(request);
|
||||
return response.messageId();
|
||||
}
|
||||
```
|
||||
|
||||
### Send FIFO Message
|
||||
```java
|
||||
public String sendFifoMessage(SqsClient sqsClient,
|
||||
String queueUrl,
|
||||
String messageBody,
|
||||
String messageGroupId) {
|
||||
SendMessageRequest request = SendMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.messageBody(messageBody)
|
||||
.messageGroupId(messageGroupId)
|
||||
.messageDeduplicationId(UUID.randomUUID().toString())
|
||||
.build();
|
||||
|
||||
SendMessageResponse response = sqsClient.sendMessage(request);
|
||||
return response.messageId();
|
||||
}
|
||||
```
|
||||
|
||||
### Send Batch Messages
|
||||
```java
|
||||
public void sendBatchMessages(SqsClient sqsClient,
|
||||
String queueUrl,
|
||||
List<String> messages) {
|
||||
List<SendMessageBatchRequestEntry> entries = IntStream.range(0, messages.size())
|
||||
.mapToObj(i -> SendMessageBatchRequestEntry.builder()
|
||||
.id(String.valueOf(i))
|
||||
.messageBody(messages.get(i))
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
SendMessageBatchRequest request = SendMessageBatchRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.entries(entries)
|
||||
.build();
|
||||
|
||||
SendMessageBatchResponse response = sqsClient.sendMessageBatch(request);
|
||||
|
||||
System.out.println("Successful: " + response.successful().size());
|
||||
System.out.println("Failed: " + response.failed().size());
|
||||
}
|
||||
```
|
||||
|
||||
## Message Processing
|
||||
|
||||
### Receive Messages with Long Polling
|
||||
```java
|
||||
public List<Message> receiveMessages(SqsClient sqsClient, String queueUrl) {
|
||||
ReceiveMessageRequest request = ReceiveMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.maxNumberOfMessages(10)
|
||||
.waitTimeSeconds(20) // Long polling
|
||||
.messageAttributeNames("All")
|
||||
.build();
|
||||
|
||||
ReceiveMessageResponse response = sqsClient.receiveMessage(request);
|
||||
return response.messages();
|
||||
}
|
||||
```
|
||||
|
||||
### Delete Message
|
||||
```java
|
||||
public void deleteMessage(SqsClient sqsClient, String queueUrl, String receiptHandle) {
|
||||
DeleteMessageRequest request = DeleteMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.receiptHandle(receiptHandle)
|
||||
.build();
|
||||
|
||||
sqsClient.deleteMessage(request);
|
||||
}
|
||||
```
|
||||
|
||||
### Delete Batch Messages
|
||||
```java
|
||||
public void deleteBatchMessages(SqsClient sqsClient,
|
||||
String queueUrl,
|
||||
List<Message> messages) {
|
||||
List<DeleteMessageBatchRequestEntry> entries = messages.stream()
|
||||
.map(msg -> DeleteMessageBatchRequestEntry.builder()
|
||||
.id(msg.messageId())
|
||||
.receiptHandle(msg.receiptHandle())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
DeleteMessageBatchRequest request = DeleteMessageBatchRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.entries(entries)
|
||||
.build();
|
||||
|
||||
sqsClient.deleteMessageBatch(request);
|
||||
}
|
||||
```
|
||||
|
||||
### Change Message Visibility
|
||||
```java
|
||||
public void changeMessageVisibility(SqsClient sqsClient,
|
||||
String queueUrl,
|
||||
String receiptHandle,
|
||||
int visibilityTimeout) {
|
||||
ChangeMessageVisibilityRequest request = ChangeMessageVisibilityRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.receiptHandle(receiptHandle)
|
||||
.visibilityTimeout(visibilityTimeout)
|
||||
.build();
|
||||
|
||||
sqsClient.changeMessageVisibility(request);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,292 @@
|
||||
# Spring Boot Integration Reference
|
||||
|
||||
## Configuration
|
||||
|
||||
### Basic Bean Configuration
|
||||
```java
|
||||
@Configuration
|
||||
public class MessagingConfiguration {
|
||||
|
||||
@Bean
|
||||
public SqsClient sqsClient() {
|
||||
return SqsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SnsClient snsClient() {
|
||||
return SnsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Properties
|
||||
```yaml
|
||||
# application.yml
|
||||
aws:
|
||||
sqs:
|
||||
queue-url: https://sqs.us-east-1.amazonaws.com/123456789012/my-queue
|
||||
sns:
|
||||
topic-arn: arn:aws:sns:us-east-1:123456789012:my-topic
|
||||
```
|
||||
|
||||
## Service Layer Integration
|
||||
|
||||
### SQS Message Service
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SqsMessageService {
|
||||
|
||||
private final SqsClient sqsClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Value("${aws.sqs.queue-url}")
|
||||
private String queueUrl;
|
||||
|
||||
public <T> void sendMessage(T message) {
|
||||
try {
|
||||
String jsonMessage = objectMapper.writeValueAsString(message);
|
||||
|
||||
SendMessageRequest request = SendMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.messageBody(jsonMessage)
|
||||
.build();
|
||||
|
||||
sqsClient.sendMessage(request);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to send SQS message", e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> List<T> receiveMessages(Class<T> messageType) {
|
||||
ReceiveMessageRequest request = ReceiveMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.maxNumberOfMessages(10)
|
||||
.waitTimeSeconds(20)
|
||||
.build();
|
||||
|
||||
ReceiveMessageResponse response = sqsClient.receiveMessage(request);
|
||||
|
||||
return response.messages().stream()
|
||||
.map(msg -> {
|
||||
try {
|
||||
return objectMapper.readValue(msg.body(), messageType);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to parse message", e);
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void deleteMessage(String receiptHandle) {
|
||||
DeleteMessageRequest request = DeleteMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.receiptHandle(receiptHandle)
|
||||
.build();
|
||||
|
||||
sqsClient.deleteMessage(request);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SNS Notification Service
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SnsNotificationService {
|
||||
|
||||
private final SnsClient snsClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Value("${aws.sns.topic-arn}")
|
||||
private String topicArn;
|
||||
|
||||
public void publishNotification(String subject, Object message) {
|
||||
try {
|
||||
String jsonMessage = objectMapper.writeValueAsString(message);
|
||||
|
||||
PublishRequest request = PublishRequest.builder()
|
||||
.topicArn(topicArn)
|
||||
.subject(subject)
|
||||
.message(jsonMessage)
|
||||
.build();
|
||||
|
||||
snsClient.publish(request);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to publish SNS notification", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Message Listener Pattern
|
||||
|
||||
### Scheduled Polling
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SqsMessageListener {
|
||||
|
||||
private final SqsClient sqsClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Value("${aws.sqs.queue-url}")
|
||||
private String queueUrl;
|
||||
|
||||
@Scheduled(fixedDelay = 5000)
|
||||
public void pollMessages() {
|
||||
ReceiveMessageRequest request = ReceiveMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.maxNumberOfMessages(10)
|
||||
.waitTimeSeconds(20)
|
||||
.build();
|
||||
|
||||
ReceiveMessageResponse response = sqsClient.receiveMessage(request);
|
||||
|
||||
response.messages().forEach(this::processMessage);
|
||||
}
|
||||
|
||||
private void processMessage(Message message) {
|
||||
try {
|
||||
// Process message
|
||||
System.out.println("Processing: " + message.body());
|
||||
|
||||
// Delete message after successful processing
|
||||
deleteMessage(message.receiptHandle());
|
||||
|
||||
} catch (Exception e) {
|
||||
// Handle error - message will become visible again
|
||||
System.err.println("Failed to process message: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteMessage(String receiptHandle) {
|
||||
DeleteMessageRequest request = DeleteMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.receiptHandle(receiptHandle)
|
||||
.build();
|
||||
|
||||
sqsClient.deleteMessage(request);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Pub/Sub Pattern Integration
|
||||
|
||||
### Configuration for Pub/Sub
|
||||
```java
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class PubSubConfiguration {
|
||||
|
||||
private final SnsClient snsClient;
|
||||
private final SqsClient sqsClient;
|
||||
|
||||
@Bean
|
||||
@DependsOn("sqsClient")
|
||||
public String setupPubSub() {
|
||||
// Create SNS topic
|
||||
String topicArn = snsClient.createTopic(CreateTopicRequest.builder()
|
||||
.name("order-events")
|
||||
.build()).topicArn();
|
||||
|
||||
// Create SQS queue
|
||||
String queueUrl = sqsClient.createQueue(CreateQueueRequest.builder()
|
||||
.queueName("order-processor")
|
||||
.build()).queueUrl();
|
||||
|
||||
// Get queue ARN
|
||||
String queueArn = sqsClient.getQueueAttributes(GetQueueAttributesRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.attributeNames(QueueAttributeName.QUEUE_ARN)
|
||||
.build()).attributes().get(QueueAttributeName.QUEUE_ARN);
|
||||
|
||||
// Subscribe SQS to SNS
|
||||
snsClient.subscribe(SubscribeRequest.builder()
|
||||
.protocol("sqs")
|
||||
.endpoint(queueArn)
|
||||
.topicArn(topicArn)
|
||||
.build());
|
||||
|
||||
return topicArn;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling Patterns
|
||||
|
||||
### Retry Mechanism
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RetryableSqsService {
|
||||
|
||||
private final SqsClient sqsClient;
|
||||
private final RetryTemplate retryTemplate;
|
||||
|
||||
public void sendMessageWithRetry(String queueUrl, String messageBody) {
|
||||
retryTemplate.execute(context -> {
|
||||
try {
|
||||
SendMessageRequest request = SendMessageRequest.builder()
|
||||
.queueUrl(queueUrl)
|
||||
.messageBody(messageBody)
|
||||
.build();
|
||||
|
||||
sqsClient.sendMessage(request);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new RetryableException("Failed to send message", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Integration
|
||||
|
||||
### LocalStack Configuration
|
||||
```java
|
||||
@TestConfiguration
|
||||
public class LocalStackMessagingConfig {
|
||||
|
||||
@Container
|
||||
static LocalStackContainer localstack = new LocalStackContainer(
|
||||
DockerImageName.parse("localstack/localstack:3.0"))
|
||||
.withServices(
|
||||
LocalStackContainer.Service.SQS,
|
||||
LocalStackContainer.Service.SNS
|
||||
);
|
||||
|
||||
@Bean
|
||||
public SqsClient sqsClient() {
|
||||
return SqsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.endpointOverride(
|
||||
localstack.getEndpointOverride(LocalStackContainer.Service.SQS))
|
||||
.credentialsProvider(StaticCredentialsProvider.create(
|
||||
AwsBasicCredentials.create(
|
||||
localstack.getAccessKey(),
|
||||
localstack.getSecretKey())))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SnsClient snsClient() {
|
||||
return SnsClient.builder()
|
||||
.region(Region.US_EAST_1)
|
||||
.endpointOverride(
|
||||
localstack.getEndpointOverride(LocalStackContainer.Service.SNS))
|
||||
.credentialsProvider(StaticCredentialsProvider.create(
|
||||
AwsBasicCredentials.create(
|
||||
localstack.getAccessKey(),
|
||||
localstack.getSecretKey())))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user