This article introduces the method of integrating SQS and Lambda, and the code is based on JAVA SDK.
POM configuration
<dependencies> <dependency> <artifactId>aws-java-sdk-sqs</artifactId> <groupId>com.amazonaws</groupId> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-core</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-events</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-log4j2</artifactId> <version>1.1.0</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-bom</artifactId> <version>1.11.272</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
SQS
China currently only supports standard Queue, not FIFO Queue. The following code uses standard Queue as an example to demonstrate the methods of creating Queue, configuring Dead Letter Queue, sending Message, receiving Message, deleting Message, and deleting Queue:
import com.amazonaws.regions.Regions; import com.amazonaws.services.sqs.AmazonSQS; import com.amazonaws.services.sqs.AmazonSQSClientBuilder; import com.amazonaws.services.sqs.model.*; import java.util. *; public class SqsUtil { private static final String ARN_ATTRIBUTE_NAME = "QueueArn"; private static AmazonSQS sqs; static { sqs = AmazonSQSClientBuilder.standard().withRegion(Regions.CN_NORTH_1).build(); } private SqsUtil() { } public static String createQueue(String queueName) { System.out.println("Creating a new SQS queue called " + queueName); CreateQueueRequest createQueueRequest = new CreateQueueRequest(queueName); Map<String, String> attributes = new HashMap<>(); // wait time to receive message attributes.put("ReceiveMessageWaitTimeSeconds", "5"); createQueueRequest.withAttributes(attributes); return sqs.createQueue(createQueueRequest).getQueueUrl(); } public static String createDeadLetterQueue(String queueName) { String queueUrl = createQueue(queueName); // Use ARN when configuring Dead Letter Queue return getQueueArn(queueUrl); } public static void configDeadLetterQueue(String queueUrl, String deadLetterQueueArn) { System.out.println("Config dead letter queue for " + queueUrl); SetQueueAttributesRequest queueAttributes = new SetQueueAttributesRequest(); Map<String, String> attributes = new HashMap<>(); // The maximum number of receptions is set to 5. When the number of receptions exceeds 5, the message will be transferred to the dead letter queue if it is not processed and deleted. attributes.put("RedrivePolicy", "{\"maxReceiveCount\":\"5\", \"deadLetterTargetArn\":\"" + deadLetterQueueArn + "\"}"); queueAttributes.setAttributes(attributes); queueAttributes.setQueueUrl (queueUrl); sqs.setQueueAttributes(queueAttributes); } public static void sendMessage(String queueUrl, String message) { System.out.println("Sending a message to " + queueUrl); SendMessageRequest request = new SendMessageRequest(); request.withQueueUrl(queueUrl); request.withMessageBody(message); Map<String, MessageAttributeValue> messageAttributes = new HashMap<>(); // Add message properties, note that there must be DataType and Value messageAttributes.put("Hello", new MessageAttributeValue().withDataType("String").withStringValue("COCO")); request.withMessageAttributes(messageAttributes); sqs.sendMessage(request); } public static void receiveMessages(String queueUrl) { System.out.println("Receiving messages from " + queueUrl); ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(queueUrl); receiveMessageRequest.setMaxNumberOfMessages(5); receiveMessageRequest.withWaitTimeSeconds(10); // To add MessageAttributeNames, otherwise it cannot be received receiveMessageRequest.setMessageAttributeNames(Arrays.asList("Hello")); List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages(); for (Message message : messages) { System.out.println("Message: " + message.getBody()); for (Map.Entry<String, MessageAttributeValue> entry : message.getMessageAttributes().entrySet()) { System.out.println(" Attribute"); System.out.println(" Name: " + entry.getKey()); System.out.println(" Value: " + entry.getValue().getStringValue()); } // Delete message System.out.println("Deleting a message."); String messageReceiptHandle = message.getReceiptHandle(); sqs.deleteMessage(new DeleteMessageRequest(queueUrl, messageReceiptHandle)); } } public static void deleteQueue(String queueUrl) { System.out.println("Deleting the queue " + queueUrl); sqs.deleteQueue(new DeleteQueueRequest(queueUrl)); } public static String getQueueArn(String queueUrl) { List<String> attributes = new ArrayList<>(); attributes.add(ARN_ATTRIBUTE_NAME); GetQueueAttributesResult queueAttributes = sqs.getQueueAttributes(queueUrl, attributes); return queueAttributes.getAttributes().get(ARN_ATTRIBUTE_NAME); } }Before running the above code, to configure credentials in the {HOME}/.aws directory, the user must have SQS permission:
[default]
aws_access_key_id = AAAAAAAAAAAAAA
aws_secret_access_key = MXXXXXXXXXXXXXXXXXXXXXX9
have a test:
// Create Dead Letter Queue String deadLetterQueueArn = createDeadLetterQueue("DeadLetterQueue"); // Create Task Queue String queueUrl = createQueue("TaskQueue"); // Configure Dead Letter Queue configDeadLetterQueue(queueUrl, deadLetterQueueArn); // send Message for (int i = 0; i < 6; i++) { sendMessage(queueUrl, "Hello COCO " + i); } // receive Message receiveMessages(queueUrl); // delete queue deleteQueue(queueUrl);
Lambda
Lambda function definitions support two ways:
- Implement the predefined interface RequestStreamHandler or RequestHandler
import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.Context; public class Hello implements RequestHandler<Request, Response> { // Request, Response are custom types public Response handleRequest(Request request, Context context) { String greetingString = String.format("Hello %s %s.", request.firstName, request.lastName); return new Response(greetingString); } }
- You don't have to implement any interface, define the handler method directly
outputType handler-name(inputType input, Context context) { ... }
inputType and outputType can be one of the following types:
- Java primitive types such as String or int.
- Predefined AWS event types in the aws-lambda-java-events library. Such as S3Event.
- Own POJO class. AWS Lambda will automatically serialize and deserialize input and output JSON based on the POJO type.
The Context object in the handler method signature can be omitted if not required.
First write a simple test case to receive SQS messages, the input parameter input is the Queue URL:
import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; public class Hello implements RequestHandler<String, String> { @Override public String handleRequest(String input, Context context) { LambdaLogger logger = context.getLogger(); logger.log("received : " + input); SqsUtil.receiveMessages(input); return "success"; } }
After the program is written, how to put it into the Lambda function? It needs to be packaged into a jar package and must contain dependency packages. Add the shade plugin to the pom:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.1.0</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Next, create a Lambda Function through the Web Console
Note: role must have lambda, Cloudwatch Logs, and SQS permissions.
Then upload the jar package and configure the Handler
Then adjust the memory configuration and timeout parameters and save.
Configure the test parameters and test it first:
Successful execution output:
Modify the code below to change the input parameter type to ScheduledEvent, which will be called using the trigger CloudWatch Events.
import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.ScheduledEvent; public class Hello implements RequestHandler<ScheduledEvent, String> { @Override public String handleRequest(ScheduledEvent input, Context context) { LambdaLogger logger = context.getLogger(); logger.log("received : " + input.toString() + "\n"); SqsUtil.receiveMessages("https://sqs.cn-north-1.amazonaws.com.cn/891245999999/TaskQueue"); return "success"; } }
After uploading, also test manually first, this time select the template Scheduled Event
After the test is successful, configure the CloudWatch Events trigger, and select Schedule expression for the Rule Type :
After saving, you can call lambda regularly, O.
Integrate SQS and Lambda: serverless architecture for asynchronous workloads
Amazon Simple Queue Service Developer Guide
Programming Model for Authoring Lambda Functions in Java
AWS SDK for Java Developer Guide
Schedule Expressions Using Rate or Cron
Getting Started with AWS Microservices and Serverless Architecture
Quickly understand AWS Lambda and easily build serverless backend
Building AWS Lambda Applications with the Serverless Application Model