[英]Micronaut with AWS Lambda and SQS
I have created simple application with Micronaut, and Graalvm and want to deploy it to the AWS Lambda and get it triggered from the SQS and process the messages.我已经使用 Micronaut 和 Graalvm 创建了简单的应用程序,并希望将其部署到 AWS Lambda 并从 SQS 触发并处理消息。 But somehow, it is not working as expected.但不知何故,它没有按预期工作。
To build this application, I use command: gradlew buildNativeLambda
要构建这个应用程序,我使用命令: gradlew buildNativeLambda
Below is my setup:以下是我的设置:
Micronaut application: Micronaut 应用程序:
Trial 1: (not working)试用1:(不工作)
import com.example.services.TestService;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Post;
import jakarta.inject.Inject;
import java.util.List;
import java.util.Map;
@Controller
public class Controller {
@Inject
private TestService testService;
@Post(consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
public Map<String, Object> indexPost(@Body List<Map<String, Object>> requestBody) throws JsonProcessingException {
return this.testService.handleRequest(requestBody.get(0));
}
}
Prepare a build and upload it to Lambda and add the following handler: io.micronaut.function.aws.proxy.MicronautLambdaHandler
准备构建并将其上传到 Lambda 并添加以下处理程序: io.micronaut.function.aws.proxy.MicronautLambdaHandler
It just works fine when I try to trigger the lambda from "Test" tab on lambda management console .当我尝试从 lambda 管理控制台上的“测试”选项卡中触发 lambda 时,它工作正常。 However, when I add the SQS as trigger, and send the message to the SQS, the message does get disappeared from the queue (thus it is being read), but I see no logs in the lambda and the functionality is also not achieved.但是,当我将 SQS 添加为触发器并将消息发送到 SQS 时,消息确实从队列中消失了(因此它正在被读取),但我在 lambda 中没有看到任何日志,并且功能也没有实现。 Thus it does not work with the SQS.因此它不适用于 SQS。
Trial 2: (not working)试验2:(不工作)
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import com.example.services.TestService;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.micronaut.core.annotation.Introspected;
import io.micronaut.function.aws.MicronautRequestHandler;
import jakarta.inject.Inject;
import java.util.List;
@Introspected
public class SQSEventHandler extends MicronautRequestHandler<SQSEvent, Void> {
@Inject
private TestService testService;
@Override
public Void execute(SQSEvent input) {
System.out.println("EVENT PROCESSING STARTS ===>");
List<SQSEvent.SQSMessage> messages = input.getRecords();
System.out.println("Number of messages:::" + messages.size());
for (SQSEvent.SQSMessage single: messages) {
try {
System.out.println("Message body::: " + single.getBody());
this.testService.handleRequest(single.getBody());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
System.out.println("<=== EVENT PROCESSING ENDS");
return null;
}
}
Prepare a build and upload it to Lambda and add the following handler: com.example.eventHandlers.SQSEventHandler
准备构建并将其上传到 Lambda 并添加以下处理程序: com.example.eventHandlers.SQSEventHandler
Now it does the same behavior with the SQS message as previous one, the message gets disappeared from the queue, but no effect in lambda.现在它对 SQS 消息执行与前一个相同的行为,消息从队列中消失,但在 lambda 中无效。
Edit - 31-08-2022:编辑 - 2022 年 8 月 31 日:
I use below body as an event to test from "Test" tab in lambda console, and this is to check the AWS Gateway event and it does works fine as we have @Controller
class.我使用下面的正文作为事件从 lambda 控制台中的“测试”选项卡进行测试,这是为了检查 AWS 网关事件,它工作正常,因为我们有@Controller
class。 Without @Controller
it fails.没有@Controller
,它会失败。
Event data:事件数据:
{
"path": "/",
"httpMethod": "POST",
"headers": {
"Accept": "application/json"
},
"body": "<my req body>"
}
But when I try to test it with the SQS event, it fails.但是当我尝试使用 SQS 事件对其进行测试时,它失败了。 I have configured com.example.eventHandlers.SQSEventHandler
as event handler in lambda for this test.我已将 com.example.eventHandlers.SQSEventHandler 配置为com.example.eventHandlers.SQSEventHandler
中的事件处理程序用于此测试。 Below is the event data which I used to test and the results:以下是我用来测试的事件数据和结果:
Event data :事件数据:
{
"Records": [
{
"messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
"receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
"body": "{\"action\": \"READ_ALL\"}",
"attributes": {
"ApproximateReceiveCount": "1",
"SentTimestamp": "1545082649183",
"SenderId": "AIDAIENQZJOLO23YVJ4VO",
"ApproximateFirstReceiveTimestamp": "1545082649185"
},
"messageAttributes": {},
"md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
"eventSource": "aws:sqs",
"eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:my-queue",
"awsRegion": "us-east-2"
}
]
}
Results:结果:
{
"statusCode": 405,
"multiValueHeaders": {
"Allow": [
"POST"
],
"Content-Type": [
"application/json"
]
},
"body": "{\"message\":\"Method Not Allowed\",\"_links\":{\"self\":{\"href\":\"https://nullnull\",\"templated\":false}},\"_embedded\":{\"errors\":[{\"message\":\"Method [GET] not allowed for URI [https://nullnull]. Allowed methods: [POST]\"}]}}",
"isBase64Encoded": false
}
If your AWS Lambda function is not generating entries in Amazon CloudWatch Logs, then it normally indicates that the Lambda function has insufficient permissions to use CloudWatch Logs. If your AWS Lambda function is not generating entries in Amazon CloudWatch Logs, then it normally indicates that the Lambda function has insufficient permissions to use CloudWatch Logs.
This can be fixed by adding permissions to the IAM Role associated with the Lambda function.这可以通过向与 Lambda function 关联的 IAM 角色添加权限来解决。 Assign it the AWSLambdaBasicExecutionRole
managed policy, which grants permission to write to CloudWatch Logs.为其分配AWSLambdaBasicExecutionRole
托管策略,该策略授予写入 CloudWatch Logs 的权限。
See: AWS managed policies for Lambda features请参阅: 针对 Lambda 功能的 AWS 托管策略
Finally made it working, if anyone is looking for the solution:最后让它工作,如果有人正在寻找解决方案:
build.gradle: build.gradle:
.
.
dependencies {
annotationProcessor 'io.micronaut:micronaut-inject-java'
annotationProcessor("io.micronaut.data:micronaut-data-processor")
implementation("io.micronaut:micronaut-jackson-databind")
implementation("io.micronaut.data:micronaut-data-hibernate-jpa")
implementation("io.micronaut.sql:micronaut-jdbc-hikari")
implementation("jakarta.annotation:jakarta.annotation-api")
runtimeOnly("ch.qos.logback:logback-classic")
runtimeOnly("mysql:mysql-connector-java")
compileOnly("org.graalvm.nativeimage:svm")
implementation("io.micronaut.aws:micronaut-function-aws") <--- IMP!!!
implementation("io.micronaut.aws:micronaut-function-aws-custom-runtime") <--- IMP!!!
implementation("io.micronaut:micronaut-validation")
testImplementation("io.micronaut:micronaut-http-client")
}
.
.
Application.java: (The starting point of the application) Application.java:(申请的起点)
public class Application extends AbstractMicronautLambdaRuntime<CustomSQSEvent, String, CustomSQSEvent, String> {
public static void main(String[] args) throws MalformedURLException {
// Micronaut.run(Application.class, args); // We don't need this now
new Application().run(args);
}
@Override
@Nullable
protected RequestHandler<CustomSQSEvent, String> createRequestHandler(String... args) {
try {
return new SQSEventHandler(createApplicationContextBuilderWithArgs(args));
} catch (ContainerInitializationException e) {
throw new ConfigurationException("Exception thrown instantiating SQSEventHandler", e);
}
}
}
CustomSQSEvent.java: (This is needed to handle the serialization/deserialization issues with the message. This is the exact copy of class com.amazonaws.services.lambda.runtime.events.SQSEvent
with few annnotations.) CustomSQSEvent.java: (This is needed to handle the serialization/deserialization issues with the message. This is the exact copy of class com.amazonaws.services.lambda.runtime.events.SQSEvent
with few annnotations.)
@Introspected <--- Very IMP!!!
public class CustomSQSEvent implements Serializable {
@JsonProperty("Records") <--- Very IMP!!!
private List<CustomSQSEvent.SQSMessage> records;
@Introspected <--- Very IMP!!!
public static class SQSMessage implements Serializable, Cloneable {
...
}
/**
* Default constructor
*/
public CustomSQSEvent() {
}
.
.
.
}
SQSEventHandler.java: (The actual magic happens here) SQSEventHandler.java:(真正的魔法发生在这里)
@Introspected
public class SQSEventHandler implements RequestHandler<CustomSQSEvent, String>, ApplicationContextProvider, Closeable {
protected final MicronautLambdaContainerHandler handler;
public SQSEventHandler() throws ContainerInitializationException {
this.handler = new MicronautLambdaContainerHandler();
}
public SQSEventHandler(ApplicationContextBuilder applicationContextBuilder) throws ContainerInitializationException {
this.handler = new MicronautLambdaContainerHandler(applicationContextBuilder);
}
public SQSEventHandler(ApplicationContext applicationContext) throws ContainerInitializationException {
this.handler = new MicronautLambdaContainerHandler(applicationContext);
}
@Override
public String handleRequest(CustomSQSEvent input, Context context) {
System.out.println("EVENT PROCESSING STARTS ===>");
TestService testService = this.getApplicationContext().getBean(TestService.class);
List<CustomSQSEvent.SQSMessage> messages = input.getRecords();
for (CustomSQSEvent.SQSMessage single: messages) {
try {
System.out.println("Message body::: " + single.getBody());
testService.handleRequest(single.getBody());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
System.out.println("<=== EVENT PROCESSING ENDS");
return "";
}
@Override
public ApplicationContext getApplicationContext() {
return this.handler.getApplicationContext();
}
@Override
public void close() {
this.getApplicationContext().close();
}
}
Removed HomeController.java
(the class which has @Controller
).删除了HomeController.java
(具有@Controller
的 class )。
And finally build the project using following command: gradlew buildNativeLambda -Pmicronaut.runtime=lambda
最后使用以下命令构建项目: gradlew buildNativeLambda -Pmicronaut.runtime=lambda
Upload the created zip
in the lambda and add the following as handler: com.example.eventHandlers.SQSEventHandler
.将创建的zip
上传到 lambda 中,并添加以下内容作为处理程序: com.example.eventHandlers.SQSEventHandler
。 This is the path to our custom event handler.这是我们自定义事件处理程序的路径。
Compiled solution from below references:从以下参考中编译的解决方案:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.