GH-789 Propagate AWS FunctionInvoker exceptions

They will be handled by the AWS runtime and properly reported and recorded.
Resolves #789
This commit is contained in:
Oleg Zhurakousky
2022-01-12 10:44:29 +01:00
parent 2ccd8b502b
commit ff9cb57741
4 changed files with 18 additions and 27 deletions

View File

@@ -30,7 +30,6 @@ import java.util.Set;
import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler; import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonDeserializer;
@@ -53,7 +52,6 @@ import org.springframework.cloud.function.utils.FunctionClassUtils;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder; import org.springframework.messaging.support.MessageBuilder;
@@ -112,27 +110,10 @@ public class FunctionInvoker implements RequestStreamHandler {
.generateMessage(payload, new MessageHeaders(Collections.emptyMap()), function.getInputType(), this.jsonMapper, context); .generateMessage(payload, new MessageHeaders(Collections.emptyMap()), function.getInputType(), this.jsonMapper, context);
} }
try { Object response = this.function.apply(requestMessage);
Object response = this.function.apply(requestMessage); byte[] responseBytes = this.buildResult(requestMessage, response);
byte[] responseBytes = this.buildResult(requestMessage, response); StreamUtils.copy(responseBytes, output);
StreamUtils.copy(responseBytes, output); // any exception should propagate
}
catch (Exception e) {
logger.error(e);
StreamUtils.copy(this.buildExceptionResult(requestMessage, e, isApiGateway), output);
}
}
private byte[] buildExceptionResult(Message<?> requestMessage, Exception exception, boolean isApiGateway) throws IOException {
if (isApiGateway) {
APIGatewayProxyResponseEvent event = new APIGatewayProxyResponseEvent();
event.setStatusCode(HttpStatus.EXPECTATION_FAILED.value());
event.setBody(exception.getMessage());
return this.jsonMapper.toJson(event);
}
else {
throw new IllegalStateException(exception);
}
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -49,6 +49,7 @@ import org.springframework.messaging.converter.AbstractMessageConverter;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
/** /**
* *
@@ -914,9 +915,14 @@ public class FunctionInvokerTests {
InputStream targetStream = new ByteArrayInputStream(this.apiGatewayEvent.getBytes()); InputStream targetStream = new ByteArrayInputStream(this.apiGatewayEvent.getBytes());
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
invoker.handleRequest(targetStream, output, null);
Map result = mapper.readValue(output.toByteArray(), Map.class); try {
assertThat(((String) result.get("body"))).startsWith("Failed to establish route, since neither were provided:"); invoker.handleRequest(targetStream, output, null);
fail();
}
catch (Exception e) {
// TODO: handle exception
}
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")

View File

@@ -37,6 +37,10 @@
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-web</artifactId> <artifactId>spring-cloud-function-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.amazonaws</groupId> <groupId>com.amazonaws</groupId>

View File

@@ -21,7 +21,7 @@ public class FunctionConfiguration {
public Function<String, String> uppercase() { public Function<String, String> uppercase() {
return value -> { return value -> {
if (value.equals("exception")) { if (value.equals("exception")) {
throw new RuntimeException("Intentional exception which should result in HTTP 417"); throw new RuntimeException("Intentional exception");
} }
else { else {
return value.toUpperCase(); return value.toUpperCase();