Skip to content

Commit 94c780b

Browse files
authored
Support multiple application properties files (incl from classpath) (feast-dev#2187)
* support spring-like properties paths Signed-off-by: pyalex <moskalenko.alexey@gmail.com> * typo Signed-off-by: pyalex <moskalenko.alexey@gmail.com>
1 parent e435d92 commit 94c780b

File tree

6 files changed

+54
-13
lines changed

6 files changed

+54
-13
lines changed

infra/charts/feast/charts/feature-server/templates/deployment.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@ spec:
8989
- java
9090
- -jar
9191
- /opt/feast/feast-serving.jar
92-
- --spring.config.location=
93-
{{- if index .Values "application.yaml" "enabled" -}}
92+
- {{- if index .Values "application.yaml" "enabled" -}}
9493
classpath:/application.yml
9594
{{- end }}
9695
{{- if index .Values "application-generated.yaml" "enabled" -}}

infra/docker-compose/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ services:
1616
- java
1717
- -jar
1818
- /opt/feast/feast-core.jar
19-
- --spring.config.location=classpath:/application.yml,file:/etc/feast/application.yml
19+
- classpath:/application.yml,file:/etc/feast/application.yml
2020

2121
jobservice:
2222
image: gcr.io/kf-feast/feast-jobservice:${FEAST_VERSION}
@@ -104,7 +104,7 @@ services:
104104
- java
105105
- -jar
106106
- /opt/feast/feast-serving.jar
107-
- --spring.config.location=classpath:/application.yml,file:/etc/feast/application.yml
107+
- classpath:/application.yml,file:/etc/feast/application.yml
108108

109109
redis:
110110
image: redis:5-alpine

java/serving/src/main/java/feast/serving/ServingGuiceApplication.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class ServingGuiceApplication {
2727
public static void main(String[] args) throws InterruptedException, IOException {
2828
if (args.length == 0) {
2929
throw new RuntimeException(
30-
"Path to application configuration file needs to be specifed via CLI");
30+
"Path to application configuration file needs to be specified via CLI");
3131
}
3232

3333
final Injector i =

java/serving/src/main/java/feast/serving/config/ApplicationProperties.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
// https://www.baeldung.com/configuration-properties-in-spring-boot
2222
// https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties
2323

24+
import com.fasterxml.jackson.annotation.JsonMerge;
25+
import com.fasterxml.jackson.annotation.OptBoolean;
2426
import feast.common.logging.config.LoggingProperties;
2527
import feast.storage.connectors.redis.retriever.RedisClusterStoreConfig;
2628
import feast.storage.connectors.redis.retriever.RedisStoreConfig;
@@ -83,6 +85,7 @@ public void setActiveStore(String activeStore) {
8385
/**
8486
* Collection of store configurations. The active store is selected by the "activeStore" field.
8587
*/
88+
@JsonMerge(OptBoolean.FALSE)
8689
private List<Store> stores = new ArrayList<>();
8790

8891
/* Metric tracing properties. */
@@ -177,6 +180,9 @@ public static class Store {
177180

178181
private Map<String, String> config = new HashMap<>();
179182

183+
// default construct for deserialization
184+
public Store() {}
185+
180186
public Store(String name, String type, Map<String, String> config) {
181187
this.name = name;
182188
this.type = type;
@@ -210,17 +216,17 @@ public StoreType getType() {
210216
return StoreType.valueOf(this.type);
211217
}
212218

219+
public void setType(String type) {
220+
this.type = type;
221+
}
222+
213223
/**
214224
* Gets the configuration to this specific store. This is a map of strings. These options are
215225
* unique to the store. Please see protos/feast/core/Store.proto for the store specific
216226
* configuration options
217227
*
218228
* @return Returns the store specific configuration
219229
*/
220-
public Map<String, String> getConfig() {
221-
return config;
222-
}
223-
224230
public RedisClusterStoreConfig getRedisClusterConfig() {
225231
return new RedisClusterStoreConfig(
226232
this.config.get("connection_string"),
@@ -235,6 +241,10 @@ public RedisStoreConfig getRedisConfig() {
235241
Boolean.valueOf(this.config.getOrDefault("ssl", "false")),
236242
this.config.getOrDefault("password", ""));
237243
}
244+
245+
public void setConfig(Map<String, String> config) {
246+
this.config = config;
247+
}
238248
}
239249

240250
public static class Server {

java/serving/src/main/java/feast/serving/config/ApplicationPropertiesModule.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@
1717
package feast.serving.config;
1818

1919
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.fasterxml.jackson.databind.ObjectReader;
2021
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
22+
import com.google.common.io.Resources;
2123
import com.google.inject.AbstractModule;
2224
import com.google.inject.Provides;
2325
import com.google.inject.Singleton;
24-
import java.io.File;
2526
import java.io.IOException;
27+
import java.nio.file.Files;
28+
import java.nio.file.Path;
2629

2730
public class ApplicationPropertiesModule extends AbstractModule {
2831
private final String[] args;
@@ -36,9 +39,37 @@ public ApplicationPropertiesModule(String[] args) {
3639
public ApplicationProperties provideApplicationProperties() throws IOException {
3740
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
3841
mapper.findAndRegisterModules();
39-
ApplicationProperties properties =
40-
mapper.readValue(new File(this.args[0]), ApplicationProperties.class);
42+
mapper.setDefaultMergeable(Boolean.TRUE);
43+
44+
ApplicationProperties properties = new ApplicationProperties();
45+
ObjectReader objectReader = mapper.readerForUpdating(properties);
46+
47+
String[] filePaths = this.args[0].split(",");
48+
for (String filePath : filePaths) {
49+
objectReader.readValue(readPropertiesFile(filePath));
50+
}
4151

4252
return properties;
4353
}
54+
55+
/**
56+
* Read file path in spring compatible format, eg classpath:/application.yml or
57+
* file:/path/application.yml
58+
*/
59+
private byte[] readPropertiesFile(String filePath) throws IOException {
60+
if (filePath.startsWith("classpath:")) {
61+
filePath = filePath.substring("classpath:".length());
62+
if (filePath.startsWith("/")) {
63+
filePath = filePath.substring(1);
64+
}
65+
66+
return Resources.toByteArray(Resources.getResource(filePath));
67+
}
68+
69+
if (filePath.startsWith("file")) {
70+
filePath = filePath.substring("file:".length());
71+
}
72+
73+
return Files.readAllBytes(Path.of(filePath));
74+
}
4475
}

java/serving/src/main/java/feast/serving/config/ServerModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package feast.serving.config;
1818

1919
import com.google.inject.AbstractModule;
20+
import com.google.inject.Provides;
2021
import feast.serving.grpc.OnlineServingGrpcServiceV2;
2122
import io.grpc.Server;
2223
import io.grpc.ServerBuilder;
@@ -30,7 +31,7 @@ protected void configure() {
3031
bind(OnlineServingGrpcServiceV2.class);
3132
}
3233

33-
// @Provides
34+
@Provides
3435
public Server provideGrpcServer(
3536
ApplicationProperties applicationProperties,
3637
OnlineServingGrpcServiceV2 onlineServingGrpcServiceV2,

0 commit comments

Comments
 (0)