micronaut-projects / micronaut-aws Goto Github PK
View Code? Open in Web Editor NEWProjects specific to integrating Micronaut and Amazon Web Services (AWS)
License: Apache License 2.0
Projects specific to integrating Micronaut and Amazon Web Services (AWS)
License: Apache License 2.0
We should support Kinesis/SNS/S3/Cognito/DynamoDB functions in Micronaut
Filters are not run when Exception Handlers are invoked and Micronaut is run through API Gateway integration.
The specific issue affecting me is that the CorsFilter is not running so CORS headers are not being added when exceptions are thrown.
Example project at https://github.com/rnielsen/micronaut-aws-apiproxy-test
curl -i http://localhost:8080/test/exception
HTTP/1.1 200 OK
X-Test-Filter: true
Exception Handled
curl -i https://3kf8ik2za4.execute-api.ap-southeast-2.amazonaws.com/dev/test/exception
HTTP/2 200
Exception Handled
Tested against io.micronaut.aws:micronaut-function-aws-api-proxy:1.1.0.BUILD-SNAPSHOT"
API Gateway assumes that the endpoints accept/produce JSON objects. This should be the default for MIcronaut as well. Currently, for example, if you are missing the Content-Type
header then @Body
objects are not populated correctly.
Hello I was going through the article here .
I decided to experiment with a far simpler version - following though the steps of the article.
Full example project:https://www.dropbox.com/s/af87ua716lh85cw/papolambda.zip
Practically is a simple λ function that returns a String nothing special.
I have tried to test it with AWS ASM
sam --version
SAM CLI, version 0.11.0
echo '{}' | sam local invoke papolambda
<properties>
<micronaut.version>1.1.0.M1</micronaut.version>
<jdk.version>8</jdk.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<exec.mainClass>io.micronaut.function.executor.FunctionApplication</exec.mainClass>
</properties>
using the template.yaml below :
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Timeout: 25
Resources:
papolambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: target/papolamda-0.1.jar
Handler: io.micronaut.function.aws.MicronautRequestStreamHandler
Runtime: java8
Where I get the following error :
START RequestId: f778d699-f29b-4410-a211-8ee626e6fb90 Version: $LATEST
java.lang.ClassNotFoundException: io.micronaut.function.aws.MicronautRequestStreamHandler
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
END RequestId: f778d699-f29b-4410-a211-8ee626e6fb90
REPORT RequestId: f778d699-f29b-4410-a211-8ee626e6fb90 Duration: 6.81 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 3 MB
While deploying to AWS it works!
AWS Cloud Map is a new service discovery service announced at re:Invent 2018.
When using the API Gateway support added in micronaut-projects/micronaut-core#540 it works until you add a custom domain name to the API Gateway, then the Lambda is invoked but return a 404.
Not sure how I can add a easy to reproduce test case since some setup for the domain is needed.
Same output as the generated API Gateway URL should be given
Tell us what happens instead
The Lambda is invoked but a HTTP 404 is generated.
The MicronautRequestHandler
currently creates its ApplicationContext
during the handleRequest
method, and uses it to inject its dependencies immediately before calling the abstract execute
method implemented by the subclass.
For anyone using Spock as their test framework, this breaks the ability to implement tests using mocked beans that are injected into the handler class. I.e., in the current flow, a test is unable to:
ApplicationContext
that will contain the mock versions of beansMockUtil.attachMock
to attach them to the current specificationexecute
I will submit a PR shortly with a proposed fix.
This request is related to this stackoverflow question: https://stackoverflow.com/questions/54747222/how-to-create-a-crud-api-on-amazon-lambda-using-micronaut
I wanted to develop a CRUD API in a single Micronaut project, including all the processing functions in it and deploying a single Lambda function.
After a lot of trial and error I managed to make it work as described in the stackoverflow answer. I'd suggest clearing up the documentation in this regard.
Also, one thing that got me stuck for a while was the need to pass a host header in the API Gateway request, otherwise io.micronaut.function.aws.proxy.MicronautAwsProxyRequest
with throw a NullPointerException at line 164: String hostHeader = awsProxyRequest.getMultiValueHeaders().getFirst(HttpHeaders.HOST);
I'd be great if it were explicitly said that we have to pass it.
What's the point of setting this header? I set it to a made up value and everything works ok ->
hostHeader = new StringBuilder().append(requestContext.getApiId())
.append(".execute-api.")
.append(region)
.append(".amazonaws.com").toString();
Docs are not clear on getting parameter store support set up, need to improve docs and working example app that uses @value annotations in a sample app that come from ssm parameter store.
I am using Micronaut 1.1.0.M2 and have created a lambda function to act as an API Gateway Lambda Authorizer (https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html).
The user sends a header (JWT-Authorization) containing a Jwt token to validate in the authorizer. I've tried different ways to access it, but I haven't found a way to get its value in the Micronaut Controller.
The authorizer testing functionality from AWS shows this info when I execute a request:
Execution log for request 9c9ecac2-3f95-11e9-9c88-c13e47b5ed68
Tue Mar 05 22:25:42 UTC 2019 : Starting authorizer: tqjif0 for request: 9c9ecac2-3f95-11e9-9c88-c13e47b5ed68
Tue Mar 05 22:25:42 UTC 2019 : Incoming identity: ****ken
Tue Mar 05 22:25:42 UTC 2019 : Endpoint request URI: https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:313316477550:function:micronaut-aws-lambda-authorizer/invocations
Tue Mar 05 22:25:42 UTC 2019 : Endpoint request headers: {x-amzn-lambda-integration-tag=9c9ecac2-3f95-11e9-9c88-c13e47b5ed68, Authorization=***************************************************************************************************************************************************************************************************************************************************************************************************************************2ea0f2, X-Amz-Date=20190305T222542Z, x-amzn-apigateway-api-id=9ed0gu04wl, X-Amz-Source-Arn=arn:aws:execute-api:eu-central-1:313316477550:9ed0gu04wl/authorizers/tqjif0, Accept=application/json, User-Agent=AmazonAPIGateway_9ed0gu04wl, X-Amz-Security-Token=FQoGZXIvYXdzEGcaDJysESX/XhVxv+8uUCK9A5euGyCl+MetHimyYVeuLi/qKKzX3zJRsaN9jV+jD+FAl6pRohhX3Q37JqZBClIHHA8vofZw+sktldCDWd2ncv2XhzUjm6YnB+YI8FsZSPfpC8hnE3b1IFF+C6Carfy61DwD+PDPVUebbTIUo0rNwzt6dIm86faV1lHYmn22biT2da7RY6QCvchEqzCcLxyB/oicQUvu09UvrL8+LOrrxoSzcZ+WAD4hv6t3nLi///pDwpMuL7f4uceCNgK6qPDSopQu+bnsK5caBiTbZLvkFzD2iSEiQrZTd28kXUhkCplaimDGEA1ebr [TRUNCATED]
Tue Mar 05 22:25:42 UTC 2019 : Endpoint request body after transformations: {"type":"TOKEN","methodArn":"arn:aws:execute-api:eu-central-1:313316477550:9ed0gu04wl/ESTestInvoke-stage/GET/","authorizationToken":"mytoken"}
Tue Mar 05 22:25:42 UTC 2019 : Sending request to https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:313316477550:function:micronaut-aws-lambda-authorizer/invocations
Tue Mar 05 22:25:47 UTC 2019 : Authorizer result body before parsing: {"statusCode":502,"multiValueHeaders":{"Content-Type":["application/json"]},"body":"{\"message\":\"Gateway timeout\"}","isBase64Encoded":false}
Tue Mar 05 22:25:47 UTC 2019 : Execution failed due to configuration error: Invalid JSON in response: {"statusCode":502,"multiValueHeaders":{"Content-Type":["application/json"]},"body":"{\"message\":\"Gateway timeout\"}","isBase64Encoded":false}
Tue Mar 05 22:25:47 UTC 2019 : AuthorizerConfigurationException
So the user header is turned into a body containing the token as "authorizationToken":"mytoken".
I've tried to bind this info like this:
@Controller("/")
class AuthorizerController {
private val logger = LoggerFactory.getLogger(LambdaAuthorizer::class.java)
@Get
fun authorize(@Body map: Map<Any, Any>): AuthPolicy {
logger.info(map.toString())
return AuthPolicy("", AuthPolicy.PolicyDocument.getDenyAllPolicy("", "", "", ""))
}
}
This call fails with:
[36m22:25:46.987�[0;39m �[1;30m[main]�[0;39m �[1;31mERROR�[0;39m �[35mi.m.f.a.p.AbstractLambdaContainerHandler�[0;39m - Error while handling request
io.micronaut.web.router.exceptions.UnsatisfiedRouteException: Required argument [Map map] not specified
at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:279)
at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:122)
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.lambda$null$1(MicronautLambdaContainerHandler.java:240)
at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:35)
As an alternative I tried with HttpRequest:
@Controller("/")
class AuthorizerController {
private val logger = LoggerFactory.getLogger(LambdaAuthorizer::class.java)
@Get
fun authorize(request: HttpRequest<String>): AuthPolicy {
logger.info(request.body.toString())
logger.info(request.headers.toString())
logger.info(request.headers.values().toString())
request.headers.forEach {
logger.info("{} - {}", it.key, it.value)
}
return AuthPolicy("", AuthPolicy.PolicyDocument.getDenyAllPolicy("", "", "", ""))
}
}
In this case the body is empty and there aren't any headers either.
START RequestId: d3a7975d-791a-4f96-b193-bdc2d1ea0b91 Version: $LATEST
�[36m22:34:27.848�[0;39m �[1;30m[pool-1-thread-5]�[0;39m �[34mINFO �[0;39m �[35mm.a.l.authorizer.LambdaAuthorizer�[0;39m - Optional.empty
�[36m22:34:27.848�[0;39m �[1;30m[pool-1-thread-5]�[0;39m �[34mINFO �[0;39m �[35mm.a.l.authorizer.LambdaAuthorizer�[0;39m - io.micronaut.function.aws.proxy.MicronautAwsProxyRequest$AwsHeaders@15d5c4bd
�[36m22:34:27.848�[0;39m �[1;30m[pool-1-thread-5]�[0;39m �[34mINFO �[0;39m �[35mm.a.l.authorizer.LambdaAuthorizer�[0;39m - []
END RequestId: d3a7975d-791a-4f96-b193-bdc2d1ea0b91
Could this be a bug or am I missing something?
We are deserialising request json dates with our custom deserialiser.
In case of invalid date format we are throwing our custom exception which ultimately gets wrapped in JSONMappingException and later on to InvalidRequestEventException.
Now since I want to send 400 BAD REQUEST in such cases but MicronautAwsProxyExceptionHandler is handling these exception by default and send
500 Internal Server Error
in place of
400 BAD REQUEST.
We tried creating our own error handler and tried replacing MicronautAwsProxyExceptionHandler but that too is not working because this exception handler is directly injected in MicronautLambdaContainerHandler.
Flow :
@Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
logger.info("Input: {}", input);
handler.proxyStream(input, output, context);
}
public void proxyStream(InputStream input, OutputStream output, Context context)
throws IOException {
try {
RequestType request = readerFor(requestTypeClass).readValue(input);
ResponseType resp = proxy(request, context);
writerFor(responseTypeClass).writeValue(output, resp);
} catch (JsonParseException e) {
log.error("Error while parsing request object stream", e);
objectMapper().writeValue(output, exceptionHandler.handle(e));
} catch (JsonMappingException e) {
log.error("Error while mapping object to RequestType class", e);
objectMapper().writeValue(output, exceptionHandler.handle(e));
} finally {
output.flush();
output.close();
}
}
@Override
public AwsProxyResponse handle(Throwable ex) {
LOG.error("Called exception handler for:", ex);
// adding a print stack trace in case we have no appender or we are running inside SAM local, where need the
// output to go to the stderr.
ex.printStackTrace();
**if (ex instanceof InvalidRequestEventException) {
return new AwsProxyResponse(500, headers,** getErrorJson(INTERNAL_SERVER_ERROR));
} else {
return new AwsProxyResponse(502, headers, getErrorJson(GATEWAY_TIMEOUT_ERROR));
}
}
Why is it doing this part, sending 500 for InvalidRequestEventException :
if (ex instanceof InvalidRequestEventException) {
return new AwsProxyResponse(500, headers,
I have a Micronaut AWS Lambda application using the api gateway feature. Thus I have the following StreamLambdaHandler
:
public class StreamLambdaHandler implements RequestStreamHandler {
private static MicronautLambdaContainerHandler handler; // <1>
static {
try {
handler = MicronautLambdaContainerHandler.getAwsProxyHandler();
} catch (ContainerInitializationException e) {
// if we fail here. We re-throw the exception to force another cold start
e.printStackTrace();
throw new RuntimeException("Could not initialize Micronaut", e);
}
}
@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context); // <2>
}
}
And this Controller:
@Controller("/")
class PongController {
@Post("/")
@Status(HttpStatus.CREATED)
fun post(): String {
println("PONG!!!!!!!")
return "{\"ping\":true}"
}
}
When invoked from AWS API Gateway, configured as proxy resource, the returned status is 200 when it shoud be 201 as defined in the controller method.
The returned status code in AWS API Gateway should be 201
The returned status code is 200
If you set up your fatJar with some static resources and configure the app like so....
micronaut:
security:
enabled: true
intercept-url-map:
-
pattern: /**
http-method: GET
access:
- isAnonymous()
router:
static-resources:
default:
enabled: true
mapping: "/**"
paths: "classpath:public"
Requests like GET /statics/icon/favicon.ico
are not proxied. Therefore gateway just returns a 404.
This makes it hard to deliver something like an SPA out of your jar.
Currently, there is only one active environment present when the function is deployed to AWS Lambda which is function
. The problem is that the same environment is for example present in tests. I know that start up time is crucial for lambda functions but there should be a way how to for example enable environment aws
based on environment variables.
Micronaut version 1.1.3
Given this simple code of a Lambda with proxy integration:
@Controller("/users")
class UserController(private val userService: UserService) {
@Get
fun getAll(): Flux<User> {
return userService.getAll()
}
}
@Singleton
class UserServiceImpl : UserService {
private val users = mutableListOf(
User("1234D", "Joe"),
User("2345C", "Lewis"))
override fun getAll(): Flux<User> {
return users.toFlux()
}
}
When calling GET /users
from the API Gateway I get and exception with the message Too many elements in the Publisher
, even though the Lambda only returns a Flux with two elements.
This is the full stacktrace:
%d [%thread] %-5level %logger - %msg%n java.lang.IndexOutOfBoundsException: Too many elements in the Publisher
at io.reactivex.internal.operators.single.SingleFromPublisher$ToSingleObserver.onNext(SingleFromPublisher.java:73) ~[task/:?]
at reactor.core.publisher.StrictSubscriber.onNext(StrictSubscriber.java:89) ~[task/:?]
at reactor.core.publisher.FluxIterable$IterableSubscription.fastPath(FluxIterable.java:311) ~[task/:?]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:198) ~[task/:?]
at reactor.core.publisher.StrictSubscriber.onSubscribe(StrictSubscriber.java:77) ~[task/:?]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139) ~[task/:?]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63) ~[task/:?]
at reactor.core.publisher.Flux.subscribe(Flux.java:7743) ~[task/:?]
at io.reactivex.internal.operators.single.SingleFromPublisher.subscribeActual(SingleFromPublisher.java:35) ~[task/:?]
at io.reactivex.Single.subscribe(Single.java:3575) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedSingle.subscribeActual(RxInstrumentedSingle.java:64) ~[task/:?]
at io.reactivex.Single.subscribe(Single.java:3575) ~[task/:?]
at io.reactivex.internal.operators.single.SingleMap.subscribeActual(SingleMap.java:34) ~[task/:?]
at io.reactivex.Single.subscribe(Single.java:3575) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedSingle.subscribeActual(RxInstrumentedSingle.java:64) ~[task/:?]
at io.reactivex.Single.subscribe(Single.java:3575) ~[task/:?]
at io.reactivex.internal.operators.single.SingleToFlowable.subscribeActual(SingleToFlowable.java:37) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:42) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14755) ~[task/:?]
at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52) ~[task/:?]
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52) ~[task/:?]
at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52) ~[task/:?]
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.internal.operators.flowable.FlowableOnErrorNext.subscribeActual(FlowableOnErrorNext.java:40) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.blockingFirst(Flowable.java:5607) ~[task/:?]
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.lambda$handleRequest$5(MicronautLambdaContainerHandler.java:274) ~[task/:?]
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52) ~[task/:?]
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.handleRequest(MicronautLambdaContainerHandler.java:206) ~[task/:?]
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.handleRequest(MicronautLambdaContainerHandler.java:73) ~[task/:?]
at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxy(AbstractLambdaContainerHandler.java:207) [task/:?]
at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxyStream(AbstractLambdaContainerHandler.java:239) [task/:?]
at com.codependent.awsintercomm.user.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:24) [task/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:350) [LambdaSandboxJava-1.0.jar:?]
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888) [LambdaSandboxJava-1.0.jar:?]
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293) [LambdaSandboxJava-1.0.jar:?]
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64) [LambdaSandboxJava-1.0.jar:?]
at java.lang.Class.forName0(Native Method) ~[?:1.8.0_201]
at java.lang.Class.forName(Class.java:348) [?:1.8.0_201]
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114) [LambdaJavaRTEntry-1.0.jar:?]
%d [%thread] %-5level %logger - %msg%n java.lang.IndexOutOfBoundsException: Too many elements in the Publisher
at io.reactivex.internal.operators.single.SingleFromPublisher$ToSingleObserver.onNext(SingleFromPublisher.java:73) ~[task/:?]
at reactor.core.publisher.StrictSubscriber.onNext(StrictSubscriber.java:89) ~[task/:?]
at reactor.core.publisher.FluxIterable$IterableSubscription.fastPath(FluxIterable.java:311) ~[task/:?]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:198) ~[task/:?]
at reactor.core.publisher.StrictSubscriber.onSubscribe(StrictSubscriber.java:77) ~[task/:?]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139) ~[task/:?]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63) ~[task/:?]
at reactor.core.publisher.Flux.subscribe(Flux.java:7743) ~[task/:?]
at io.reactivex.internal.operators.single.SingleFromPublisher.subscribeActual(SingleFromPublisher.java:35) ~[task/:?]
at io.reactivex.Single.subscribe(Single.java:3575) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedSingle.subscribeActual(RxInstrumentedSingle.java:64) ~[task/:?]
at io.reactivex.Single.subscribe(Single.java:3575) ~[task/:?]
at io.reactivex.internal.operators.single.SingleMap.subscribeActual(SingleMap.java:34) ~[task/:?]
at io.reactivex.Single.subscribe(Single.java:3575) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedSingle.subscribeActual(RxInstrumentedSingle.java:64) ~[task/:?]
at io.reactivex.Single.subscribe(Single.java:3575) ~[task/:?]
at io.reactivex.internal.operators.single.SingleToFlowable.subscribeActual(SingleToFlowable.java:37) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:42) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14755) ~[task/:?]
at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52) ~[task/:?]
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52) ~[task/:?]
at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52) ~[task/:?]
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.internal.operators.flowable.FlowableOnErrorNext.subscribeActual(FlowableOnErrorNext.java:40) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14752) ~[task/:?]
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) ~[task/:?]
at io.reactivex.Flowable.subscribe(Flowable.java:14805) ~[task/:?]
at io.reactivex.Flowable.blockingFirst(Flowable.java:5607) ~[task/:?]
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.lambda$handleRequest$5(MicronautLambdaContainerHandler.java:274) ~[task/:?]
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52) ~[task/:?]
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.handleRequest(MicronautLambdaContainerHandler.java:206) ~[task/:?]
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.handleRequest(MicronautLambdaContainerHandler.java:73) ~[task/:?]
at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxy(AbstractLambdaContainerHandler.java:207) [task/:?]
at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxyStream(AbstractLambdaContainerHandler.java:239) [task/:?]
at com.codependent.awsintercomm.user.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:24) [task/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:350) [LambdaSandboxJava-1.0.jar:?]
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888) [LambdaSandboxJava-1.0.jar:?]
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293) [LambdaSandboxJava-1.0.jar:?]
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64) [LambdaSandboxJava-1.0.jar:?]
at java.lang.Class.forName0(Native Method) ~[?:1.8.0_201]
at java.lang.Class.forName(Class.java:348) [?:1.8.0_201]
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114) [LambdaJavaRTEntry-1.0.jar:?]
java.lang.IndexOutOfBoundsException: Too many elements in the Publisher
at io.reactivex.internal.operators.single.SingleFromPublisher$ToSingleObserver.onNext(SingleFromPublisher.java:73)
at reactor.core.publisher.StrictSubscriber.onNext(StrictSubscriber.java:89)
at reactor.core.publisher.FluxIterable$IterableSubscription.fastPath(FluxIterable.java:311)
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:198)
at reactor.core.publisher.StrictSubscriber.onSubscribe(StrictSubscriber.java:77)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63)
at reactor.core.publisher.Flux.subscribe(Flux.java:7743)
at io.reactivex.internal.operators.single.SingleFromPublisher.subscribeActual(SingleFromPublisher.java:35)
at io.reactivex.Single.subscribe(Single.java:3575)
at io.micronaut.reactive.rxjava2.RxInstrumentedSingle.subscribeActual(RxInstrumentedSingle.java:64)
at io.reactivex.Single.subscribe(Single.java:3575)
at io.reactivex.internal.operators.single.SingleMap.subscribeActual(SingleMap.java:34)
at io.reactivex.Single.subscribe(Single.java:3575)
at io.micronaut.reactive.rxjava2.RxInstrumentedSingle.subscribeActual(RxInstrumentedSingle.java:64)
at io.reactivex.Single.subscribe(Single.java:3575)
at io.reactivex.internal.operators.single.SingleToFlowable.subscribeActual(SingleToFlowable.java:37)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:42)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14755)
at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.internal.operators.flowable.FlowableOnErrorNext.subscribeActual(FlowableOnErrorNext.java:40)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.subscribe(Flowable.java:14752)
at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
at io.reactivex.Flowable.subscribe(Flowable.java:14805)
at io.reactivex.Flowable.blockingFirst(Flowable.java:5607)
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.lambda$handleRequest$5(MicronautLambdaContainerHandler.java:274)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.handleRequest(MicronautLambdaContainerHandler.java:206)
at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.handleRequest(MicronautLambdaContainerHandler.java:73)
at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxy(AbstractLambdaContainerHandler.java:207)
at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxyStream(AbstractLambdaContainerHandler.java:239)
at com.codependent.awsintercomm.user.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:350)
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293)
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)
END RequestId: 846a2af9-559b-447f-9e47-43e66cda14b9
The behaviour is as expected when starting the project as a normal Micronaut application and requesting that endpoint: [{"id":"1234D","name":"Joe"},{"id":"2345C","name":"Lewis"}]
see serviceDiscoveryRoute53.adoc
I have a route for a multipart file upload which works fine when running the service as a standalone application:
@Post("/attachments", consumes = [MediaType.MULTIPART_FORM_DATA])
fun uploadImage(file: CompletedFileUpload) : HttpResponse<Any> {
...
return HttpResponse.created("Created")
}
When testing the route with curl -v -X POST http://localhost:8080/attachments -H 'Content-type: multipart/form-data' -F file=@/path/image.jpg
everything works fine.
When I deploy the service as a Lambda with API Gateway access, the file does not seem to make it to the controller: io.micronaut.web.router.exceptions.UnsatisfiedRouteException: Required argument [CompletedFileUpload file] not specified
.
All other routes in my application work correctly even if deployed to AWS Lambda + API Gateway so I suspect there might be an issue with parsing the API Gateway input in the Micronaut AWS Proxy Handler.
MicronautLambdaContainerHandler.getAwsProxyHandler()
in a serverless or CloudFormation environment. An example is here.io.micronaut:micronaut-management
application.yml
:endpoints:
info:
enabled: true
sensitive: false
/info
endpoint, relative to the API Gateway endpointExpected an info endpoint result.
An exception is logged in CloudWatch and the endpoint returns a 502 error.
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [refreshScope] of class: io.micronaut.runtime.context.scope.refresh.RefreshInterceptor
Message: No bean of type [io.micronaut.runtime.context.scope.refresh.RefreshScope] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: new InfoEndpoint(InfoAggregator infoAggregator,[InfoSource[] infoSources]) --> new $BuildInfoSourceDefinition$Intercepted(ResourceResolver resourceResolver,String buildPropertiesPath,BeanContext beanContext,[Interceptor[] interceptors]) --> new RefreshInterceptor([RefreshScope refreshScope])
All AWS functions (with or without API Gateway) run with the Environment.FUNCTION
environment. The built-in BuildInfoSource
is a @Refreshable
bean and RefreshScope
is disabled when running in Environment.FUNCTION
. Therefore this could probably be easily fixed by creating an abstract base class of the BuildInfoSource
bean and two concrete versions, one that's @Refreshable
and @Requires(notEnv = Environment.FUNCTION)
and the other @Requires(notEnv = Environment.FUNCTION)
and NOT @Refreshable
.
https://github.com/micronaut-projects/micronaut-aws/tree/master/examples/api-gateway-example
A sample project is available here using micronaut-aws-lambda-proxy 1.1.0.RC1: https://github.com/codependent/micronaut-aws-lambda-proxy
The problem is with a controller like this:
@Controller("/ping")
class PingController {
private val logger = LoggerFactory.getLogger(javaClass)
@Post("/")
@Status(HttpStatus.CREATED)
fun createPing(@Body ping: Ping): Ping {
logger.info("ping {}", ping)
return ping
}
}
The Ping argument is correctly unmarshalled (as seen in the logs)...
[36m15:07:27.873[0;39m [1;30m[pool-1-thread-5][0;39m [34mINFO [0;39m [35mc.c.m.awslambda.web.PingController[0;39m - ping Ping(value=myval)
... and returned from the controller, but AWS API Gateway shows this error:
Thu Feb 21 15:41:31 UTC 2019 : Endpoint response body before transformations: {"statusCode":201,"statusDescription":"Created","multiValueHeaders":{"Content-Type":["application/json"]},"body":"{\"value\":\"myval\"}","isBase64Encoded":false}
Thu Feb 21 15:41:31 UTC 2019 : Endpoint response headers: {Date=Thu, 21 Feb 2019 15:41:31 GMT, Content-Type=application/json, Content-Length=161, Connection=keep-alive, x-amzn-RequestId=1d9becec-16b4-42fe-bde6-4dcec2f0d86c, x-amzn-Remapped-Content-Length=0, X-Amz-Executed-Version=$LATEST, X-Amzn-Trace-Id=root=1-5c6ec6ab-faea1670ec1ce53b5d0b5b6e;sampled=0}
Thu Feb 21 15:41:31 UTC 2019 : Execution failed due to configuration error: Malformed Lambda proxy response
For some reason the response doesn't follow the expected format
https://aws.amazon.com/premiumsupport/knowledge-center/malformed-502-api-gateway/
When I tried Custom GraalVM Native Runtimes
on this page, I got a warning, and the generated binary didn't contain Java Runtime.
https://micronaut-projects.github.io/micronaut-aws/latest/guide/#customRuntimes
The warning message is as follows.
[server:6] classlist: 18,170.22 ms
[server:6] (cap): 1,760.69 ms
[server:6] setup: 4,722.97 ms
[server:6] analysis: 44,020.50 ms
Warning: Aborting stand-alone image build. No instances are allowed in the image heap for a class that is initialized or reinitialized at image runtime: com.amazonaws.serverless.proxy.model.ContainerConfig. Try marking this class for build-time initialization with --initialize-at-build-time=com.amazonaws.serverless.proxy.model.ContainerConfig
Detailed message:
Trace: field io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.config
Warning: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
[server:67] classlist: 6,628.29 ms
[server:67] (cap): 1,597.73 ms
[server:67] setup: 4,403.42 ms
[server:67] (typeflow): 6,819.44 ms
[server:67] (objects): 1,793.49 ms
[server:67] (features): 253.99 ms
[server:67] analysis: 9,047.10 ms
[server:67] (clinit): 261.85 ms
[server:67] universe: 845.08 ms
[server:67] (parse): 1,915.63 ms
[server:67] (inline): 2,603.30 ms
[server:67] (compile): 15,898.98 ms
[server:67] compile: 20,901.04 ms
[server:67] image: 731.63 ms
[server:67] write: 244.38 ms
[server:67] [total]: 43,122.48 ms
Warning: Image 'server' is a fallback image that requires a JDK for execution (use --no-fallback to suppress fallback image generation).
When I added --initialize-at-build-time=com.amazonaws.serverless.proxy.model
to native-image.properties
and built again, native-image command succeeded.
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)
GraalVM 19.0.0 and 19.0.2
Docker Desktop Community 2.0.0.3
macOS Mojave 10.14.5
I create an app using CLI command:
mn create-app my-app --features aws-api-gateway-graal --build maven
After I build a jar file, I'm trying to run it using generated deploy.sh
file.
Trying to call a Lambda i'm constantly got:
No bin/java and no environment variable JAVA_HOME
while using micronaut version 1.1
When using the FunctionInitializer the Pojo that is parsed with jackson does not read the @jsonproperties annotation.
Json
{
"Records": ["test1", "test2"]
}
Pojo
@Introspected
public class SqsEvent {
@JsonProperty("Records")
private List<String> records;
public List<String> getRecords() {
return records;
}
public void setRecords(List<String> records) {
this.records = records;
}
}
function
@Singleton
public class SqsFunction extends FunctionInitializer {
public void execute(SqsEvent event) {
event.getRecords(); // is always empty
}
}
while using ObjectMapper directly it works
SqsEvent event = mapper.readValue(json, SqsEvent.class);
event.getRecords(); // is filled
I am using mn version 1.1.0.M1
Created app using mn create-app my-app --features aws-api-gateway-graal
Trying to deploy it and it not working, gives error in CloudWatch:
START RequestId: 6ed53036-dc55-4c60-ae7a-ba91ad8f988c Version: $LATEST
io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout
Request loop failed with: Read Timeout
END RequestId: 6ed53036-dc55-4c60-ae7a-ba91ad8f988c
REPORT RequestId: 6ed53036-dc55-4c60-ae7a-ba91ad8f988c Duration: 15015.13 ms Billed Duration: 15000 ms Memory Size: 128 MB Max Memory Used: 95 MB
2019-02-13T09:29:19.172Z 6ed53036-dc55-4c60-ae7a-ba91ad8f988c Task timed out after 15.02 seconds
Example project here: https://github.com/huksley/micronaut-aws-api-gateway-graal
For security Amazon recommends the user set the skill ID on their skill so the SDK will match that ID with the incoming request and reject it if it doesn't match. You can force disable this to make it work in the AWS Developer Console, but it's not recommended. Need to add a configuration value to the application.yml and have the
Will send a PR soon.
Exception Handlers are not run when Micronaut is run through API Gateway integration. Any exceptions that occur return a 502 Gateway Timeout to the client.
This affects custom error handlers as well as @Valid annotations
Example project at https://github.com/rnielsen/micronaut-aws-apiproxy-test
curl -i http://localhost:8080/test/exception
HTTP/1.1 200 OK
Exception Handled
curl -i https://3kf8ik2za4.execute-api.ap-southeast-2.amazonaws.com/dev/test/exception
HTTP/2 502
{"message":"Gateway timeout"}
Tested against io.micronaut.aws:micronaut-function-aws-api-proxy:1.1.0.RC3"
When a method has multiple media types in it's @consumes annotation eg. @Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON})
, it always returns a 415 response when deployed through the AWS API Gateway integration.
This specifically affects the default /login and /oauth/token endpoints when using Micronaut Authentication (along with Issue #22)
Problem seems to be MicronautLambdaContainerHandler.java assuming only one MediaType.
Example project at https://github.com/rnielsen/micronaut-aws-apiproxy-test
curl -i -H "Content-Type: application/json" -X POST -d '{"name":"Test"}' http://localhost:8080/test/multipleConsumes
HTTP/1.1 200 OK
{"name":"Test"}
curl -i -H "Content-Type: application/json" -X POST -d '{"name":"Test"}' https://3kf8ik2za4.execute-api.ap-southeast-2.amazonaws.com/dev/test/multipleConsumes
HTTP/2 415
Tested against io.micronaut.aws:micronaut-function-aws-api-proxy:1.1.0.RC3"
Follow steps from https://bitbucket.org/traycho/micronaut-examples/src/master/
Application should behave same running standard jar or graalvm compiled binary.
Executing curl -G http://localhost:3000/ping
should result into { "message": "ping"}
Executing curl -G http://localhost:3000/ping
results into {}
Using HttpResponse returned by controller methods results into {} empty body.
Checkout code from
https://bitbucket.org/traycho/micronaut-examples/src/master/
Adding SQS support: queue configuration, annotations for producers and consumers, ...
mn create-app aws-api-gateway-test --features aws-api-gateway
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.QueryValue;
@Controller
public class TestController {
@Get("/books/{book}")
public String book(String book) {
return "{\"book\": \"" + book + "\"}";
}
}
./gradlew clean build && sam local start-api --template sam.yaml
http://127.0.0.1:3000/books/The%20Name%20of%20the%20Wind
or http://127.0.0.1:3000/books/The Name of the Wind
Example project can be checked out from here: https://github.com/lkonya/micronaut-aws-api-gateway-test.git
HTTP 200 - successfully decode URL path
{
"book": "The Name of the Wind"
}
HTTP 500 - Internal Server Error
Server:
com.amazonaws.serverless.exceptions.InvalidRequestEventException: Invalid Request: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Wind
at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:123)
at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:48)
at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxy(AbstractLambdaContainerHandler.java:204)
at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxyStream(AbstractLambdaContainerHandler.java:239)
at aws.api.gateway.test.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:350)
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293)
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)
Caused by: java.lang.IllegalArgumentException: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Wind
at java.net.URI.create(URI.java:852)
at io.micronaut.function.aws.proxy.MicronautAwsProxyRequest.getUri(MicronautAwsProxyRequest.java:174)
at io.micronaut.http.HttpRequest.getPath(HttpRequest.java:85)
at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:79)
... 15 more
Caused by: java.net.URISyntaxException: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Wind
at java.net.URI$Parser.fail(URI.java:2848)
at java.net.URI$Parser.checkChars(URI.java:3021)
at java.net.URI$Parser.parseHierarchical(URI.java:3105)
at java.net.URI$Parser.parse(URI.java:3053)
at java.net.URI.<init>(URI.java:588)
at java.net.URI.create(URI.java:850)
... 18 more
END RequestId: 65a9e328-1710-402a-ad10-f3515714416b
REPORT RequestId: 65a9e328-1710-402a-ad10-f3515714416b Duration: 186.98 ms Billed Duration: 200 ms Memory Size: 512 MB Max Memory Used: 34 MB
[2019-04-19 09:32:28.966] " + NO_REQUEST_ID + " INFO i.m.f.a.p.AbstractLambdaContainerHandler - Starting Lambda Container Handler
[2019-04-19 09:32:29.086] " + NO_REQUEST_ID + " INFO i.m.c.e.DefaultEnvironment - Established active environments: [function]
com.amazonaws.serverless.exceptions.InvalidRequestEventException: Invalid Request: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Windr at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:123)r at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:48)r at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxy(AbstractLambdaContainerHandler.java:204)r at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxyStream(AbstractLambdaContainerHandler.java:239)r at aws.api.gateway.test.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:24)r at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)r at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)r at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)r at java.lang.reflect.Method.invoke(Method.java:498)r at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:350)r at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888)r at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293)r at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)r at java.lang.Class.forName0(Native Method)r at java.lang.Class.forName(Class.java:348)r at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)rCaused by: java.lang.IllegalArgumentException: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Windr at java.net.URI.create(URI.java:852)r at io.micronaut.function.aws.proxy.MicronautAwsProxyRequest.getUri(MicronautAwsProxyRequest.java:174)r at io.micronaut.http.HttpRequest.getPath(HttpRequest.java:85)r at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:79)r ... 15 common frames omittedrCaused by: java.net.URISyntaxException: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Windr at java.net.URI$Parser.fail(URI.java:2848)r at java.net.URI$Parser.checkChars(URI.java:3021)r at java.net.URI$Parser.parseHierarchical(URI.java:3105)r at java.net.URI$Parser.parse(URI.java:3053)r at java.net.URI.<init>(URI.java:588)r at java.net.URI.create(URI.java:850)r ... 18 common frames omittedr
com.amazonaws.serverless.exceptions.InvalidRequestEventException: Invalid Request: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Windr at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:123)r at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:48)r at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxy(AbstractLambdaContainerHandler.java:204)r at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxyStream(AbstractLambdaContainerHandler.java:239)r at aws.api.gateway.test.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:24)r at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)r at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)r at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)r at java.lang.reflect.Method.invoke(Method.java:498)r at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:350)r at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888)r at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293)r at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)r at java.lang.Class.forName0(Native Method)r at java.lang.Class.forName(Class.java:348)r at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)rCaused by: java.lang.IllegalArgumentException: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Windr at java.net.URI.create(URI.java:852)r at io.micronaut.function.aws.proxy.MicronautAwsProxyRequest.getUri(MicronautAwsProxyRequest.java:174)r at io.micronaut.http.HttpRequest.getPath(HttpRequest.java:85)r at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:79)r ... 15 common frames omittedrCaused by: java.net.URISyntaxException: Illegal character in path at index 61: https://1234567890.execute-api.eu-central-1.amazonaws.com/The Name of the Windr at java.net.URI$Parser.fail(URI.java:2848)r at java.net.URI$Parser.checkChars(URI.java:3021)r at java.net.URI$Parser.parseHierarchical(URI.java:3105)r at java.net.URI$Parser.parse(URI.java:3053)r at java.net.URI.<init>(URI.java:588)r at java.net.URI.create(URI.java:850)r ... 18 common frames omittedr
2019-04-19 11:32:31 No Content-Type given. Defaulting to 'application/json'.
2019-04-19 11:32:31 127.0.0.1 - - [19/Apr/2019 11:32:31] "GET /The%20Name%20of%20the%20Wind HTTP/1.1" 500 -
I write very simple demo java project with aws custom runtime. (micronaut.version: 1.1.0.M1)
It has just one controller
@Controller
public class HelloController {
@Get("/hello")
public String sayHello() {
return "hello";
}
}
project: https://github.com/eisig/lambda-demo2
When invoked from AWS API Gateway. The first call will return as exptected.
Then invoke it again a few minutes later, the api return {"message": "Internal server error"}
.
Logs:
10:17:44.149 [main]INFO i.m.f.a.p.AbstractLambdaContainerHandler - Starting Lambda Container Handler
10:17:44.282 [main]INFO i.m.context.env.DefaultEnvironment - Established active environments: [function]
START RequestId: f3689953-f4f9-43a6-96b7-a5ebef02b48f Version: $LATEST
END RequestId: f3689953-f4f9-43a6-96b7-a5ebef02b48f
REPORT RequestId: f3689953-f4f9-43a6-96b7-a5ebef02b48f Init Duration: 2325.18 ms Duration: 553.63 ms Billed Duration: 2900 ms Memory Size: 704 MB Max Memory Used: 118 MB
START RequestId: 10754fbd-1cf2-4963-8392-fb10d6aed231 Version: $LATEST
io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
at io.reactivex.internal.operators.flowable.FlowableCreate$BaseEmitter.onError(FlowableCreate.java:275)
at io.micronaut.http.client.DefaultHttpClient$10.exceptionCaught(DefaultHttpClient.java:1816)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.channel.ChannelInboundHandlerAdapter.exceptionCaught(ChannelInboundHandlerAdapter.java:131)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.channel.ChannelInboundHandlerAdapter.exceptionCaught(ChannelInboundHandlerAdapter.java:131)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.channel.ChannelInboundHandlerAdapter.exceptionCaught(ChannelInboundHandlerAdapter.java:131)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireExceptionCaught(CombinedChannelDuplexHandler.java:426)
at io.netty.channel.ChannelHandlerAdapter.exceptionCaught(ChannelHandlerAdapter.java:87)
at io.netty.channel.CombinedChannelDuplexHandler$1.fireExceptionCaught(CombinedChannelDuplexHandler.java:147)
at io.netty.channel.ChannelInboundHandlerAdapter.exceptionCaught(ChannelInboundHandlerAdapter.java:131)
at io.netty.channel.CombinedChannelDuplexHandler.exceptionCaught(CombinedChannelDuplexHandler.java:233)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.handler.timeout.ReadTimeoutHandler.readTimedOut(ReadTimeoutHandler.java:98)
at io.netty.handler.timeout.ReadTimeoutHandler.channelIdle(ReadTimeoutHandler.java:90)
at io.netty.handler.timeout.IdleStateHandler$ReaderIdleTimeoutTask.run(IdleStateHandler.java:494)
at io.netty.handler.timeout.IdleStateHandler$AbstractIdleTask.run(IdleStateHandler.java:466)
at io.netty.util.concurrent.PromiseTask$RunnableAdapter.call(PromiseTask.java:38)
at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:127)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout
at io.micronaut.http.client.exceptions.ReadTimeoutException.<clinit>(ReadTimeoutException.java:26)
at io.micronaut.http.client.DefaultHttpClient.lambda$null$25(DefaultHttpClient.java:1055)
at io.reactivex.internal.operators.flowable.FlowableOnErrorNext$OnErrorNextSubscriber.onError(FlowableOnErrorNext.java:103)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onError$1(InstrumentedSubscriber.java:96)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onError(InstrumentedSubscriber.java:100)
at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutSubscriber.onTimeout(FlowableTimeoutTimed.java:139)
at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutTask.run(FlowableTimeoutTimed.java:170)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
... 1 more
Exception in thread "nioEventLoopGroup-1-3" io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
at io.reactivex.internal.operators.flowable.FlowableCreate$BaseEmitter.onError(FlowableCreate.java:275)
at io.micronaut.http.client.DefaultHttpClient$10.exceptionCaught(DefaultHttpClient.java:1816)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.channel.ChannelInboundHandlerAdapter.exceptionCaught(ChannelInboundHandlerAdapter.java:131)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.channel.ChannelInboundHandlerAdapter.exceptionCaught(ChannelInboundHandlerAdapter.java:131)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.channel.ChannelInboundHandlerAdapter.exceptionCaught(ChannelInboundHandlerAdapter.java:131)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireExceptionCaught(CombinedChannelDuplexHandler.java:426)
at io.netty.channel.ChannelHandlerAdapter.exceptionCaught(ChannelHandlerAdapter.java:87)
at io.netty.channel.CombinedChannelDuplexHandler$1.fireExceptionCaught(CombinedChannelDuplexHandler.java:147)
at io.netty.channel.ChannelInboundHandlerAdapter.exceptionCaught(ChannelInboundHandlerAdapter.java:131)
at io.netty.channel.CombinedChannelDuplexHandler.exceptionCaught(CombinedChannelDuplexHandler.java:233)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:285)
at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:264)
at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:256)
at io.netty.handler.timeout.ReadTimeoutHandler.readTimedOut(ReadTimeoutHandler.java:98)
at io.netty.handler.timeout.ReadTimeoutHandler.channelIdle(ReadTimeoutHandler.java:90)
at io.netty.handler.timeout.IdleStateHandler$ReaderIdleTimeoutTask.run(IdleStateHandler.java:494)
at io.netty.handler.timeout.IdleStateHandler$AbstractIdleTask.run(IdleStateHandler.java:466)
at io.netty.util.concurrent.PromiseTask$RunnableAdapter.call(PromiseTask.java:38)
at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:127)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout
at io.micronaut.http.client.exceptions.ReadTimeoutException.<clinit>(ReadTimeoutException.java:26)
at io.micronaut.http.client.DefaultHttpClient.lambda$null$25(DefaultHttpClient.java:1055)
at io.reactivex.internal.operators.flowable.FlowableOnErrorNext$OnErrorNextSubscriber.onError(FlowableOnErrorNext.java:103)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onError$1(InstrumentedSubscriber.java:96)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onError(InstrumentedSubscriber.java:100)
at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutSubscriber.onTimeout(FlowableTimeoutTimed.java:139)
at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutTask.run(FlowableTimeoutTimed.java:170)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
... 1 more
io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout
at io.micronaut.http.client.exceptions.ReadTimeoutException.<clinit>(ReadTimeoutException.java:26)
at io.micronaut.http.client.DefaultHttpClient.lambda$null$25(DefaultHttpClient.java:1055)
at io.reactivex.internal.operators.flowable.FlowableOnErrorNext$OnErrorNextSubscriber.onError(FlowableOnErrorNext.java:103)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onError$1(InstrumentedSubscriber.java:96)
at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onError(InstrumentedSubscriber.java:100)
at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutSubscriber.onTimeout(FlowableTimeoutTimed.java:139)
at io.reactivex.internal.operators.flowable.FlowableTimeoutTimed$TimeoutTask.run(FlowableTimeoutTimed.java:170)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Request loop failed with: Read Timeout
END RequestId: 10754fbd-1cf2-4963-8392-fb10d6aed231
REPORT RequestId: 10754fbd-1cf2-4963-8392-fb10d6aed231 Duration: 2199.86 ms Billed Duration: 2200 ms Memory Size: 704 MB Max Memory Used: 120 MB
RequestId: 10754fbd-1cf2-4963-8392-fb10d6aed231 Error: Runtime exited without providing a reason
Runtime.ExitError
10:20:17.201 [main]INFO i.m.f.a.p.AbstractLambdaContainerHandler - Starting Lambda Container Handler
10:20:17.341 [main]INFO i.m.context.env.DefaultEnvironment - Established active environments: [function]
START RequestId: 5c454603-1575-4cfe-8a1e-426e5c4eb154 Version: $LATEST
I feel like I must be misunderstanding something. MicronautRequestStreamHandler
is a Lambda-specific stream handler that takes a lambda Context
object. The Context
object contains a functionName
property which specifies the declared name of the lambda function. Confusingly, this value is never referenced when the RequestStreamHandler is attempting to map its current execution context to a @FunctionBean
function name.
Is there a reason why MicronautRequestStreamHandler
does not out-of-the-box override AbstractExecutor.resolveFunctionName
and return Context.getFunctionName()
? It's straightforward enough for me to do myself, but I don't understand why it's not the default behaviour.
The MicronautAwsProxyRequest.AwsParameters.getAll() method does not return parameter values but instead returns the parameter name. I believe the following:
return strings.stream().map(v -> decodeValue(name,name.toString())).collect(Collectors.toList());
Should be:
return strings.stream().map(v -> decodeValue(name,v.toString())).collect(Collectors.toList());
The exception handler for the derived exception is always invoked.
Sometimes, apparently "at random" the RuntimeException handler is invoked.
AWS Lambda (Java 8, standard AWS runtime)
Having com.amazonaws.services.lambda.runtime.events.S3Event
as input to the MicronautRequestHandler
like below causes an ClassCastException when the execute method is invoked from the handler.
public class MyFunction extends MicronautRequestHandler<S3Event, String> { ... }
...
@Override
public String execute(S3Event event) { ... }
Error
{
"errorMessage": "java.util.LinkedHashMap cannot be cast to com.amazonaws.services.lambda.runtime.events.S3Event",
"errorType": "java.lang.ClassCastException",
"stackTrace": [
"test.package.MyFunction.execute(MyFunction.java:40)",
"io.micronaut.function.aws.MicronautRequestHandler.handleRequest(MicronautRequestHandler.java:37)",
"sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
"sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
"java.lang.reflect.Method.invoke(Method.java:498)"
]
}
Trying to use the example: micronaut-aws/examples/api-proxy-graal-custom-runtime-example/
I am forced to use micronautVersion=1.1.0.M2
if not I get the error - Could not find or load main class io.micronaut.graal.reflect.GraalClassLoadingAnalyzer
But with 1.1.0.M2 deployed to Lambda I get below error
{
"errorMessage": "Error starting Micronaut container: No bean of type [io.micronaut.jackson.codec.JsonMediaTypeCodec] exists. Ensure the class is declared a bean and if you are using Java or Kotlin make sure you have enabled annotation processing."
}
The suggested StreamLambdaHandler
is not very friendly to testing. @MicronautTest
doesn't seem to be compatible with testing the handler. I'm using Gru for AWS API Gateway Proxy for testing to ensure the API Gateway integration works.
I had to come up with the following implementation to be able to reset the application context stored statically.
public class StreamLambdaHandler implements RequestStreamHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(StreamLambdaHandler.class);
private static MicronautLambdaContainerHandler handler;
static {
reset();
}
/**
* Resets the current handler. For testing purposes only.
*/
public static void reset() {
reset(b -> {});
}
/**
* Resets the current handler. For testing purposes only.
*
* @param configuration builder customizer
*/
public static void reset(Consumer<ApplicationContextBuilder> configuration) {
try {
ApplicationContextBuilder builder = ApplicationContext.build();
configuration.accept(builder);
handler = MicronautLambdaContainerHandler.getAwsProxyHandler(builder);
} catch (ContainerInitializationException e) {
// if we fail here. We re-throw the exception to force another cold start
if (LOGGER.isErrorEnabled()) {
LOGGER.error("Exception in container initialization", e);
}
throw new IllegalStateException("Could not initialize Micronaut", e);
}
}
/**
* Return the application context. For testing purposes only.
*/
public static ApplicationContext getApplicationContext() {
if (handler == null) {
reset();
}
return handler.getApplicationContext();
}
@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context);
}
}
Then I am able to test the handler as follows:
void setup() {
MicronautHandler.reset()
MicronautHandler.applicationContext.with { ApplicationContext context ->
context.environment.addPropertySource('test.properties', [
'app.server.url': SOME_APP_SERVER_URL,
])
context.registerSingleton(CaptchaService, captchaService)
context.registerSingleton(AuthTokenService, managerTokenService, Qualifiers.byName('managerTokenService'))
}
}
Given the below controller action:
@Get("/render-html")
@Produces(MediaType.TEXT_HTML)
public ModelAndView getHtmlFromRenderEngine(Context context) {
ModelAndView mav = new ModelAndView("home", CollectionUtils.mapOf("firstname", "Luke", "lastname", "Skywalker"));
return mav;
}
When executing the action through AWS API Gateway (via the micronaut function-aws-api-proxy) the result will be:
{"view":"home","model":{"firstname":Luke,"lastname":"Skywalker"}}
The correct result should be rendered "home" template using the configured render engine.
Created an application using the aws-api-gateway-graal feature following the link
https://micronaut-projects.github.io/micronaut-aws/latest/guide/#customRuntimes
I used the following fix to build
#49
Micronaut version 1.2.1
After this i deploy to an aws lambda with an api gateway, call the ping endpoint and response is 200. Calling the same endpoint after adding a custom domain in AWS that uses the api gateway causes a 502 status along with the following error in the lambda logs which gets repeated seemingly until the lambda times out.
11:40:34 WARNING: The sunec native library, required by the SunEC provider, could not be loaded. This library is usually shipped as part of the JDK and can be found under <JAVA_HOME>/jre/lib//libsunec.so. It is loaded at run time via System.loadLibrary("sunec"), the first time services from SunEC are accessed. To use this provider's services the java.library.path system property needs to be set a
11:40:34 START RequestId: 54b57a52-049a-4303-aeb3-60763a20944b Version: $LATEST
11:40:34 END RequestId: 54b57a52-049a-4303-aeb3-60763a20944b
11:40:34 REPORT RequestId: 54b57a52-049a-4303-aeb3-60763a20944b Duration: 18.89 ms Billed Duration: 300 ms Memory Size: 3008 MB Max Memory Used: 77 MB Init Duration: 264.85 ms XRAY TraceId: 1-5d80c631-77a3481d1600ee0d1c4ebba9 SegmentId: 14e6aa5d6d1cebaf Sampled: true
11:40:38 START RequestId: 667ef73d-b2a7-4bc4-8423-9517dbbe294c Version: $LATEST
11:40:38 Invocation with requestId [667ef73d-b2a7-4bc4-8423-9517dbbe294c] failed: com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.getContainerConfig()java.lang.NoSuchMethodError: com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.getContainerConfig()
11:40:38 at com.amazonaws.serverless.proxy.internal.SecurityUtils.isValidHost(SecurityUtils.java:63)
11:40:38 at io.micronaut.function.aws.proxy.MicronautAwsProxyRequest.getUri(MicronautAwsProxyRequest.java:167)
11:40:38 at io.micronaut.http.HttpRequest.getPath(HttpRequest.java:85)
11:40:38 at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:79)
11:40:38 at io.micronaut.function.aws.proxy.MicronautRequestReader.readRequest(MicronautRequestReader.java:48)
11:40:38 at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxy(AbstractLambdaContainerHandler.java:204)
11:40:38 at io.micronaut.function.aws.runtime.MicronautLambdaRuntime.startRuntimeApiEventLoop(MicronautLambdaRuntime.java:129)
11:40:38 at io.micronaut.function.aws.runtime.MicronautLambdaRuntime.main(MicronautLambdaRuntime.java:75)
mn create-app aws-api-gateway-test --features aws-api-gateway
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.QueryValue;
import javax.annotation.Nullable;
@Controller
public class BookController {
@Get("/optional/books{?max,offset}")
public String booksWithOptionalQueryParams(@Nullable String max, @Nullable Integer offset) {
return "{\"max\": " + max + ", \"offset\": " + offset + "}";
}
@Get("/mandatory/books")
public String booksWithQueryParams(@QueryValue String max, @QueryValue Integer offset) {
return "{\"max\": " + max + ", \"offset\": " + offset + "}";
}
}
./gradlew clean build && sam local start-api --template sam.yaml
http://127.0.0.1:3000/optional/books?max=10&offset=10
or http://127.0.0.1:3000/mandatory/books?max=10&offset=10
Example project can be checked out from here: https://github.com/lkonya/micronaut-aws-api-gateway-test.git
HTTP 200 - successfully parsed URI query strings into query params
{
"max": 10,
"offset": 10
}
HTTP 400 - Bad Request
Client:
{
"_links": {
"self": {
"href": "https://1234567890.execute-api.eu-central-1.amazonaws.com/books",
"templated": false
}
},
"message": "Required argument [String max] not specified",
"path": "/max"
}
Server:
[2019-04-19 09:08:10.813] " + NO_REQUEST_ID + " INFO i.m.f.a.p.AbstractLambdaContainerHandler - Starting Lambda Container Handler
[2019-04-19 09:08:10.917] " + NO_REQUEST_ID + " INFO i.m.c.e.DefaultEnvironment - Established active environments: [function]
[2019-04-19 09:08:12.759] aa14e611-63d3-4b9e-8a6e-e75dba87e94a ERROR i.m.h.s.n.c.UnsatisfiedRouteHandler - io.micronaut.function.aws.proxy.MicronautAwsProxyRequest@415e0bcb (Bad Request): Required argument [String max] not specified
2019-04-19 11:08:13 No Content-Type given. Defaulting to 'application/json'.
2019-04-19 11:08:13 127.0.0.1 - - [19/Apr/2019 11:08:13] "GET /books?max=10&offset=10 HTTP/1.1" 400 -
There may be a problem with the unmarshalling process in annotated controllers running as lambdas with proxy integration. The full description of the problem can be found in Stackoverflow: https://stackoverflow.com/questions/54769250/micronaut-lambda-with-proxy-cant-unmarshal-object-from-json-body-io-micronaut-w
A Sample project is available here: https://github.com/codependent/micronaut-aws-lambda-proxy
This issue refers to the following function: https://github.com/codependent/micronaut-aws-authentication-function
It's a basic function that generates a JWT token:
@FunctionBean("micronaut-aws-authentication-function")
class MicronautAwsAuthenticationFunction : Function<Credentials, AuthenticationResponse> {
private val logger = LoggerFactory.getLogger(javaClass)
override fun apply(t: Credentials): AuthenticationResponse {
logger.info("Authenticating {} - {}", t.user, t.password)
return if (t.user == "jose" && t.password == "MyPassword") {
//HMAC
val algorithm = Algorithm.HMAC256("secret")
val token = JWT.create()
.withIssuer("MicronautAwsAuthenticationFunction")
.withSubject(t.user)
.sign(algorithm)
logger.info("Generated token {}", token)
AuthenticationResponse(token)
} else {
logger.info("Incorrect user/password")
AuthenticationResponse()
}
}
}
Normally (warm behaviour) this AWS executes really fast (~5ms):
Duration
2.05 ms
Billed duration
100 ms
Resources configured
320 MB
Max memory used
153 MB
However the cold start is extremely slow ~20s. I was expecting that Micronaut-based java8 lambdas start way faster than normal Java applications but this shows there's no improvement at all.
The function is invoked directly in the Lambda web console, through the io.micronaut.function.aws.MicronautRequestStreamHandler
handler and has 320MB RAM assigned. Also, there's no VPC configured:
Duration
19475.13 ms
Billed duration
19500 ms
Resources configured
320 MB
Max memory used
154 MB
I wonder if there may be something wrong about my setup/implementation or this is the expected behaviour and you guys have found similar times for the cold start. In this case, do you have a way to improve this horrible cold start times??
The link to Example application https://github.com/micronaut-projects/micronaut-aws/tree/master/examples/api-proxy-example responds with 404.
Incoming Cookies are not available via httpRequest.getCookies()
when Micronaut is run through API Gateway integration. Outgoing cookies are added to the response correctly and the cookies are available via httpRequest.getHeaders().get("Cookie")
The specific issue affecting me is that Micronaut JWT authentication via Cookies is not allowing access to secured pages after login.
Example project at https://github.com/rnielsen/micronaut-aws-apiproxy-test
curl -i --cookie test=value http://localhost:8080/test/checkCookies
HTTP/1.1 200 OK
{"cookieHeader":"test=value","cookies":[{"nettyCookie":{"secure":false,"httpOnly":false},"name":"test","value":"value","secure":false,"maxAge":-9223372036854775808,"httpOnly":false}]}
curl -i --cookie test=value https://3kf8ik2za4.execute-api.ap-southeast-2.amazonaws.com/dev/test/checkCookies
HTTP/2 200
{"cookieHeader":"test=value"}
Tested against io.micronaut.aws:micronaut-function-aws-api-proxy:1.1.3.BUILD-SNAPSHOT"
Thanks for reporting an issue for Micronaut, please review the task list below before submitting the
issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed.
NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Stack Overflow (http://stackoverflow.com/tags/micronaut) or Gitter (https://gitter.im/micronautfw/). DO NOT use the issue tracker to ask questions.
Validate the POJO and either return a 400 Bad request or 201 for Created.
The controller works fine when I run it stand alone or via test but it fails when I deploy it with AWS and invoke it via API Gateway. I get the following error:
io.micronaut.web.router.exceptions.UnsatisfiedRouteException: Required argument [BrandRepresentation brand] not specified at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:279) at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:122) at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.executeRoute(MicronautLambdaContainerHandler.java:312) at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.lambda$null$1(MicronautLambdaContainerHandler.java:233) at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:35) at io.reactivex.Flowable.subscribe(Flowable.java:14805) at io.reactivex.Flowable.subscribe(Flowable.java:14752) at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) at io.reactivex.Flowable.subscribe(Flowable.java:14805) at io.reactivex.Flowable.subscribe(Flowable.java:14755) at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52) at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52) at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52) at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29) at io.reactivex.Flowable.subscribe(Flowable.java:14805) at io.reactivex.Flowable.subscribe(Flowable.java:14752) at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) at io.reactivex.Flowable.subscribe(Flowable.java:14805) at io.reactivex.internal.operators.flowable.FlowableOnErrorNext.subscribeActual(FlowableOnErrorNext.java:40) at io.reactivex.Flowable.subscribe(Flowable.java:14805) at io.reactivex.Flowable.subscribe(Flowable.java:14752) at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68) at io.reactivex.Flowable.subscribe(Flowable.java:14805) at io.reactivex.Flowable.blockingFirst(Flowable.java:5607) at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.lambda$handleRequest$5(MicronautLambdaContainerHandler.java:274) at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52) at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.handleRequest(MicronautLambdaContainerHandler.java:206) at io.micronaut.function.aws.proxy.MicronautLambdaContainerHandler.handleRequest(MicronautLambdaContainerHandler.java:73) at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxy(AbstractLambdaContainerHandler.java:207) at io.micronaut.function.aws.proxy.AbstractLambdaContainerHandler.proxyStream(AbstractLambdaContainerHandler.java:239) at com.identityguard.config.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:36) at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888) at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293) at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)
-N/A
the scripts from api-gateway-proxy-graal
feature lack the initial line to build the application. it would make more sense to me if each of the script starts with ./gradlew build
.
This improvement request is related to this question from stackoverflow: https://stackoverflow.com/questions/54768208/is-it-possible-to-access-the-whole-request-information-in-a-micronaut-lambda-wit
The point is sometimes it may be necessary to access multiple values from the request, headers, query params, body...
In a controller like this:
fun postPing(@Header("Host") host: String): String {
logger.info("PARAM {}", host)
return "{\"pong\":true}"
}
if we wanted to access a bunch of headers, plus a body, etc... we could end up with a method with too many parameters.
Could you consider allowing us to use some kind of class that gives us access to all the request information?
Spring Cloud Function solved this by means of a Message class, that encapsulates all the request info and gives access to the unmarshaled body: http://cloud.spring.io/spring-cloud-static/spring-cloud-function/2.0.1.RELEASE/single/spring-cloud-function.html#_java_8_function_support
If the user writes a function using Message (from spring-messaging) it will receive and transmit headers from any adapter that supports key-value metadata (e.g. HTTP headers). Here are the details.
I tried to upgrade our app to Micronaut 1.2 (from 1.0.4), but our AWS lambda functions stopped working. Here is the Exception I get:
Failed to inject value for parameter [refreshScope] of class: io.micronaut.runtime.context.scope.refresh.RefreshInterceptor
Message: No bean of type [io.micronaut.runtime.context.scope.refresh.RefreshScope] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: DispatcherFunction.setTaskProcessor([TaskProcessor taskProcessor])
--> TaskProcessor.setWorkerServices([WorkerService[] workerServices])
--> BrandWorkerService.setBrandComputationService([BrandComputationService brandComputationService])
--> BrandComputationService.setServicesClient([ServicesClient servicesClient])
--> new ServicesClient$Intercepted(BeanContext beanContext,Qualifier qualifier,[Interceptor[] interceptors])
--> new FunctionClientAdvice(FunctionDiscoveryClient discoveryClient,[FunctionInvokerChooser functionInvokerChooser])
--> new DefaultFunctionInvokerChooser([FunctionInvokerChooser[] choosers])
--> new AWSLambdaFunctionExecutor([AWSLambdaAsync asyncClient],ByteBufferFactory byteBufferFactory,JsonMediaTypeCodec jsonMediaTypeCodec,ExecutorService ioExecutor)
--> new $AWSLambdaAsyncClientFactory$AwsLambdaAsyncClient0Definition$Intercepted(BeanContext beanContext,Qualifier qualifier,[Interceptor[] interceptors])
--> new RefreshInterceptor([RefreshScope refreshScope]): io.micronaut.context.exceptions.DependencyInjectionException
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [refreshScope] of class: io.micronaut.runtime.context.scope.refresh.RefreshInterceptor
I did a quick search and found #45 which looks similar, but we don't have the micronaut-management
module configured for our AWS functions. Still, it gave me a hint that this might be the problem:
public class AWSLambdaAsyncClientFactory {
(...)
@Refreshable
@Requires(beans = AWSLambdaConfiguration.class)
AWSLambdaAsync awsLambdaAsyncClient() {
Maybe the @Refreshable
annotation is causing this? If not, please can you let me know how to get AWS functions working again? This is a blocker to our upgrade.
Followed the README for examples/api-proxy-graal-custom-runtime-example, but it failed on the generation of reflect.json step because "Could not find or load main class io.micronaut.graal.reflect.GraalClassLoadingAnalyzer" from the fat jar.
What would prevent the dependency for io.micronaut.graal.reflect.GraalClassLoadingAnalyzer from being included in the fat jar?
docker build . -t example-micronaut-runtime
Sending build context to Docker daemon 101.4kB
Step 1/23 : FROM gradle:5.1.1-jdk-alpine as builder
---> 5c0d09610520
Step 2/23 : COPY --chown=gradle:gradle . /home/application
---> 66174f284cf3
Step 3/23 : WORKDIR /home/application
---> Running in 5022a517fe3b
Removing intermediate container 5022a517fe3b
---> 46df1fe4052d
Step 4/23 : RUN gradle build --no-daemon
---> Running in 040019a2a7a4Welcome to Gradle 5.1.1!
Here are the highlights of this release:
- Control which dependencies can be retrieved from which repositories
- Production-ready configuration avoidance APIs
For more details see https://docs.gradle.org/5.1.1/release-notes.html
To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: https://docs.gradle.org/5.1.1/userguide/gradle_daemon.html.
Daemon will be stopped at the end of the build stopping after processingTask :compileJava
Note: Creating bean classes for 1 type elementsTask :processResources
Task :classes
Task :jar
Task :startScripts
Task :distTar
Task :distZip
Task :buildZip
Task :shadowJar
Task :startShadowScripts
Task :shadowDistTar
Task :shadowDistZip SKIPPED
Task :assemble
Note: Creating bean classes for 1 type elementsTask :compileTestJava
Task :processTestResources NO-SOURCE
Task :testClasses
Task :test
Task :check
Task :buildDeprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.1.1/userguide/command_line_interface.html#sec:command_line_warningsBUILD SUCCESSFUL in 1m 3s
12 actionable tasks: 12 executed
Removing intermediate container 040019a2a7a4
---> 0c38484359aa
Step 5/23 : FROM amazonlinux:2017.03.1.20170812 as graalvm
---> 28b6d09fbbe4
Step 6/23 : ENV LANG=en_US.UTF-8
---> Using cache
---> 7398562eec93
Step 7/23 : RUN yum install -y gcc gcc-c++ libc6-dev zlib1g-dev curl bash zlib zlib-devel zip && rm -rf /var/cache/yum
---> Using cache
---> 81d6ebb3a4cc
Step 8/23 : ENV GRAAL_VERSION 1.0.0-rc11
---> Using cache
---> 9b97ba12f988
Step 9/23 : ENV GRAAL_FILENAME graalvm-ce-${GRAAL_VERSION}-linux-amd64.tar.gz
---> Using cache
---> 55b1ea6c8754
Step 10/23 : RUN curl -4 -L https://github.com/oracle/graal/releases/download/vm-${GRAAL_VERSION}/${GRAAL_FILENAME} -o /tmp/${GRAAL_FILENAME}
---> Using cache
---> 3b7018178301
Step 11/23 : RUN tar -zxvf /tmp/${GRAAL_FILENAME} -C /tmp && mv /tmp/graalvm-ce-${GRAAL_VERSION} /usr/lib/graalvm
---> Using cache
---> bc1aee2930e6
Step 12/23 : RUN rm -rf /tmp/*
---> Using cache
---> 368abba502e1
Step 13/23 : CMD ["/usr/lib/graalvm/bin/native-image"]
---> Using cache
---> 4298fc3e16f3
Step 14/23 : FROM graalvm
---> 4298fc3e16f3
Step 15/23 : COPY --from=builder /home/application/ /home/application/
---> f82f11a2ac51
Step 16/23 : WORKDIR /home/application
---> Running in d7756549dc4c
Removing intermediate container d7756549dc4c
---> add59665ea7a
Step 17/23 : RUN /usr/lib/graalvm/bin/java -cp build/libs/.jar io.micronaut.graal.reflect.GraalClassLoadingAnalyzer reflect.json
---> Running in c1b3d24d9497
Error: Could not find or load main class io.micronaut.graal.reflect.GraalClassLoadingAnalyzer
The command '/bin/sh -c /usr/lib/graalvm/bin/java -cp build/libs/.jar io.micronaut.graal.reflect.GraalClassLoadingAnalyzer reflect.json' returned a non-zero code: 1
The latest docs regarding using Custom GraalVM Native Runtimes
mention the example application: https://github.com/micronaut-projects/micronaut-aws/tree/master/examples/api-proxy-graal-custom-runtime-example
But this example is actually not in the repo.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.