GH-1014 Fix CustomRuntimeEventLoop to default to RoutingFunction
Resolves #1014
This commit is contained in:
@@ -33,6 +33,7 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
|
|
||||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||||
import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper;
|
import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper;
|
||||||
|
import org.springframework.cloud.function.context.config.RoutingFunction;
|
||||||
import org.springframework.cloud.function.json.JsonMapper;
|
import org.springframework.cloud.function.json.JsonMapper;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.context.SmartLifecycle;
|
import org.springframework.context.SmartLifecycle;
|
||||||
@@ -218,7 +219,8 @@ public final class CustomRuntimeEventLoop implements SmartLifecycle {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FunctionInvocationWrapper locateFunction(Environment environment, FunctionCatalog functionCatalog, HttpHeaders httpHeaders) {
|
private FunctionInvocationWrapper locateFunction(Environment environment, FunctionCatalog functionCatalog,
|
||||||
|
HttpHeaders httpHeaders) {
|
||||||
MediaType contentType = httpHeaders.getContentType();
|
MediaType contentType = httpHeaders.getContentType();
|
||||||
String handlerName = environment.getProperty("DEFAULT_HANDLER");
|
String handlerName = environment.getProperty("DEFAULT_HANDLER");
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
@@ -257,6 +259,15 @@ public final class CustomRuntimeEventLoop implements SmartLifecycle {
|
|||||||
function = functionCatalog.lookup(handlerName, contentType.toString());
|
function = functionCatalog.lookup(handlerName, contentType.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (function == null) {
|
||||||
|
function = functionCatalog.lookup(RoutingFunction.FUNCTION_NAME, "application/json");
|
||||||
|
if (function != null && logger.isInfoEnabled()) {
|
||||||
|
logger.info("Will default to RoutingFunction, since multiple functions available in FunctionCatalog."
|
||||||
|
+ "Expecting 'spring.cloud.function.definition' or 'spring.cloud.function.routing-expression' as Message headers. "
|
||||||
|
+ "If invocation is over API Gateway, Message headers can be provided as HTTP headers.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Assert.notNull(function, "Failed to locate function. Tried locating default function, "
|
Assert.notNull(function, "Failed to locate function. Tried locating default function, "
|
||||||
+ "function by 'DEFAULT_HANDLER', '_HANDLER' env variable as well as'spring.cloud.function.definition'. "
|
+ "function by 'DEFAULT_HANDLER', '_HANDLER' env variable as well as'spring.cloud.function.definition'. "
|
||||||
+ "Functions available in catalog are: " + functionCatalog.getNames(null));
|
+ "Functions available in catalog are: " + functionCatalog.getNames(null));
|
||||||
|
|||||||
@@ -40,7 +40,4 @@ RUN ln -s /usr/lib/gradle/bin/gradle /usr/bin/gradle
|
|||||||
|
|
||||||
ENV JAVA_HOME /usr/lib/graalvm
|
ENV JAVA_HOME /usr/lib/graalvm
|
||||||
|
|
||||||
ENTRYPOINT ["sh"]
|
WORKDIR /function-sample-aws-native
|
||||||
COPY . /home
|
|
||||||
WORKDIR /home
|
|
||||||
ENTRYPOINT ["sh"]
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
# Introduction
|
||||||
|
|
||||||
|
This example shows GraaalVM native spring-cloud-function application. The application itself is very simple and contains two functions - `uppercase` & `lowercase`.
|
||||||
|
Unless specific value is specified as `handler`, the application will fall back on `RoutingFunction` where you can pass the routing instruction
|
||||||
|
via `spring.cloud.function.definition` Message header. If using API Gateway you can pass such header as HTTP header.
|
||||||
|
|
||||||
# To run
|
# To run
|
||||||
|
|
||||||
## If you are on OSX Apple M1 Pro (arch64)
|
## If you are on OSX Apple M1 Pro (arch64)
|
||||||
@@ -11,7 +17,7 @@ $ docker build -t "al2-graalvm19:native-uppercase" .
|
|||||||
Start the container
|
Start the container
|
||||||
|
|
||||||
```
|
```
|
||||||
$ docker run -dit al2-graalvm19:native-uppercase
|
$ docker run -dit -v `pwd`:`pwd` -w `pwd` -v ~/.m2:/root/.m2 al2-graalvm19:native-uppercase
|
||||||
```
|
```
|
||||||
|
|
||||||
Now navigate to the image terminal. Your working directory is alredy set for the root of the project. You can verify it by executing `ls`.
|
Now navigate to the image terminal. Your working directory is alredy set for the root of the project. You can verify it by executing `ls`.
|
||||||
|
|||||||
@@ -148,5 +148,40 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spring-snapshots</id>
|
||||||
|
<name>Spring Snapshots</name>
|
||||||
|
<url>https://repo.spring.io/snapshot</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>spring-milestones</id>
|
||||||
|
<name>Spring Milestones</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>spring-releases</id>
|
||||||
|
<name>Spring Releases</name>
|
||||||
|
<url>https://repo.spring.io/release</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-snapshots</id>
|
||||||
|
<name>Spring Snapshots</name>
|
||||||
|
<url>https://repo.spring.io/snapshot</url>
|
||||||
|
</pluginRepository>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-milestones</id>
|
||||||
|
<name>Spring Milestones</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
</pluginRepository>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-releases</id>
|
||||||
|
<name>Spring Releases</name>
|
||||||
|
<url>https://repo.spring.io/release</url>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<useDefaultExcludes>true</useDefaultExcludes>
|
<useDefaultExcludes>true</useDefaultExcludes>
|
||||||
<fileMode>0775</fileMode>
|
<fileMode>0775</fileMode>
|
||||||
<includes>
|
<includes>
|
||||||
<include>native-uppercase</include>
|
<include>function-sample-aws-native</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
</fileSets>
|
</fileSets>
|
||||||
|
|||||||
@@ -2,17 +2,35 @@ package com.example.demo;
|
|||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.function.context.DefaultMessageRoutingHandler;
|
||||||
|
import org.springframework.cloud.function.context.MessageRoutingCallback;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class NativeUppercaseApplication {
|
public class NativeUppercaseApplication {
|
||||||
|
|
||||||
|
Log logger = LogFactory.getLog(NativeUppercaseApplication.class);
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(NativeUppercaseApplication.class, args);
|
SpringApplication.run(NativeUppercaseApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MessageRoutingCallback customRouter() {
|
||||||
|
return new MessageRoutingCallback() {
|
||||||
|
@Override
|
||||||
|
public String routingResult(Message<?> message) {
|
||||||
|
logger.info("Received message: " + message);
|
||||||
|
return (String) message.getHeaders().get("spring.cloud.function.definition");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Function<String, String> uppercase() {
|
public Function<String, String> uppercase() {
|
||||||
return v -> {
|
return v -> {
|
||||||
@@ -21,4 +39,12 @@ public class NativeUppercaseApplication {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Function<String, String> lowercase() {
|
||||||
|
return v -> {
|
||||||
|
System.out.println("Lowercasing " + v);
|
||||||
|
return v.toUpperCase();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
cd ${LAMBDA_TASK_ROOT:-.}
|
cd ${LAMBDA_TASK_ROOT:-.}
|
||||||
|
|
||||||
./native-uppercase -Dlogging.level.org.springframework=DEBUG
|
./function-sample-aws-native -Dlogging.level.org.springframework=DEBUG
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.springframework.messaging.rsocket.RSocketRequester;
|
|||||||
import org.springframework.util.MimeTypeUtils;
|
import org.springframework.util.MimeTypeUtils;
|
||||||
|
|
||||||
|
|
||||||
@SpringBootTest(properties = {"spring.rsocket.server.port=55555"})
|
@SpringBootTest(properties = {"spring.rsocket.server.port=55551"})
|
||||||
@ExtendWith(DemoApplicationTests.TestRule.class)
|
@ExtendWith(DemoApplicationTests.TestRule.class)
|
||||||
public class DemoApplicationTests {
|
public class DemoApplicationTests {
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public class DemoApplicationTests {
|
|||||||
" }\n" +
|
" }\n" +
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
this.rsocketRequesterBuilder.tcp("localhost", 55555)
|
this.rsocketRequesterBuilder.tcp("localhost", 55551)
|
||||||
.route("hire")
|
.route("hire")
|
||||||
.metadata("{\"content-type\":\"application/cloudevents+json\"}", MimeTypeUtils.APPLICATION_JSON)
|
.metadata("{\"content-type\":\"application/cloudevents+json\"}", MimeTypeUtils.APPLICATION_JSON)
|
||||||
.data(payload)
|
.data(payload)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-stream</artifactId>
|
<artifactId>spring-cloud-stream</artifactId>
|
||||||
<version>4.0.0-SNAPSHOT</version>
|
<version>4.0.2-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- RabbitMQ - only needed if you intend to invoke via RabbitMQ -->
|
<!-- RabbitMQ - only needed if you intend to invoke via RabbitMQ -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
spring.cloud.function.definition=hire
|
|
||||||
spring.cloud.stream.bindings.hire-in-0.binder=rabbit
|
|
||||||
spring.cloud.stream.bindings.hire-out-0.binder=kafka
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
spring:
|
||||||
|
cloud:
|
||||||
|
stream:
|
||||||
|
bindings:
|
||||||
|
hire-in-0:
|
||||||
|
binder: rabbit1
|
||||||
|
hire-out-0:
|
||||||
|
binder: kafka1
|
||||||
|
binders:
|
||||||
|
rabbit1:
|
||||||
|
type: rabbit
|
||||||
|
kafka1:
|
||||||
|
type: kafka
|
||||||
|
function:
|
||||||
|
definition: hire
|
||||||
Reference in New Issue
Block a user