From 0ea7a5c0bbdbb77c71a76c81f8e9a117df8206b6 Mon Sep 17 00:00:00 2001 From: Terence Date: Thu, 29 Oct 2020 14:53:55 +0800 Subject: [PATCH 1/3] Add serving integration test for updated feature type Signed-off-by: Terence --- .../feast/serving/it/ServingServiceIT.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/serving/src/test/java/feast/serving/it/ServingServiceIT.java b/serving/src/test/java/feast/serving/it/ServingServiceIT.java index f933bbbba8..428dd598b9 100644 --- a/serving/src/test/java/feast/serving/it/ServingServiceIT.java +++ b/serving/src/test/java/feast/serving/it/ServingServiceIT.java @@ -419,4 +419,75 @@ public void shouldReturnNotFoundForDiffType() { assertEquals(expectedFieldValuesList, featureResponse.getFieldValuesList()); } + + @Test + public void shouldReturnNotFoundForUpdatedType() { + String projectName = "default"; + String entityName = "driver_id"; + String featureTableName = "rides"; + + ImmutableList entities = ImmutableList.of(entityName); + ImmutableMap features = + ImmutableMap.of( + "trip_cost", + ValueProto.ValueType.Enum.INT64, + "trip_distance", + ValueProto.ValueType.Enum.STRING, + "trip_empty", + ValueProto.ValueType.Enum.DOUBLE, + "trip_wrong_type", + ValueProto.ValueType.Enum.STRING); + + TestUtils.applyFeatureTable( + coreClient, projectName, featureTableName, entities, features, 7200); + + // Sleep is necessary to ensure caching (every 10s) of updated FeatureTable is done + try { + Thread.sleep(15000); + } catch (InterruptedException e) { + } + + ValueProto.Value entityValue = ValueProto.Value.newBuilder().setInt64Val(1).build(); + // Instantiate EntityRows + GetOnlineFeaturesRequestV2.EntityRow entityRow1 = + DataGenerator.createEntityRow(entityName, DataGenerator.createInt64Value(1), 100); + ImmutableList entityRows = ImmutableList.of(entityRow1); + + // Instantiate FeatureReferences + ServingAPIProto.FeatureReferenceV2 featureReference = + DataGenerator.createFeatureReference("rides", "trip_distance"); + + ImmutableList featureReferences = + ImmutableList.of(featureReference); + + // Build GetOnlineFeaturesRequestV2 + GetOnlineFeaturesRequestV2 onlineFeatureRequest = + TestUtils.createOnlineFeatureRequest(projectName, featureReferences, entityRows); + GetOnlineFeaturesResponse featureResponse = + servingStub.getOnlineFeaturesV2(onlineFeatureRequest); + + ImmutableMap expectedValueMap = + ImmutableMap.of( + entityName, + entityValue, + FeatureV2.getFeatureStringRef(featureReference), + DataGenerator.createEmptyValue()); + + ImmutableMap expectedStatusMap = + ImmutableMap.of( + entityName, + GetOnlineFeaturesResponse.FieldStatus.PRESENT, + FeatureV2.getFeatureStringRef(featureReference), + GetOnlineFeaturesResponse.FieldStatus.NOT_FOUND); + + GetOnlineFeaturesResponse.FieldValues expectedFieldValues = + GetOnlineFeaturesResponse.FieldValues.newBuilder() + .putAllFields(expectedValueMap) + .putAllStatuses(expectedStatusMap) + .build(); + ImmutableList expectedFieldValuesList = + ImmutableList.of(expectedFieldValues); + + assertEquals(expectedFieldValuesList, featureResponse.getFieldValuesList()); + } } From a653fea2cc028f2ccf176c15d6803aa727896a00 Mon Sep 17 00:00:00 2001 From: Terence Date: Mon, 2 Nov 2020 14:20:38 +0800 Subject: [PATCH 2/3] Make cache refresh configurable Signed-off-by: Terence --- .../feast/serving/config/FeastProperties.java | 21 +++++++++++++++++++ .../serving/config/SpecServiceConfig.java | 3 ++- serving/src/main/resources/application.yml | 1 + .../feast/serving/it/ServingServiceIT.java | 10 ++++++--- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/serving/src/main/java/feast/serving/config/FeastProperties.java b/serving/src/main/java/feast/serving/config/FeastProperties.java index c7a7b03a19..6c0b33fa0a 100644 --- a/serving/src/main/java/feast/serving/config/FeastProperties.java +++ b/serving/src/main/java/feast/serving/config/FeastProperties.java @@ -86,6 +86,9 @@ public void setCoreAuthentication(CoreAuthenticationProperties coreAuthenticatio this.coreAuthentication = coreAuthentication; } + /* Feast Core port to connect to. */ + @Positive private int coreCacheRefreshInterval; + private SecurityProperties security; @Bean @@ -220,6 +223,24 @@ public void setCoreGrpcPort(int coreGrpcPort) { this.coreGrpcPort = coreGrpcPort; } + /** + * Gets CachedSpecService refresh interval. + * + * @return CachedSpecService refresh interval + */ + public int getCoreCacheRefreshInterval() { + return coreCacheRefreshInterval; + } + + /** + * Sets CachedSpecService refresh interval. + * + * @param coreCacheRefreshInterval CachedSpecService refresh interval + */ + public void setCoreCacheRefreshInterval(int coreCacheRefreshInterval) { + this.coreCacheRefreshInterval = coreCacheRefreshInterval; + } + /** * Sets the collection of configured stores. * diff --git a/serving/src/main/java/feast/serving/config/SpecServiceConfig.java b/serving/src/main/java/feast/serving/config/SpecServiceConfig.java index 75b77a29a0..32dbcec77c 100644 --- a/serving/src/main/java/feast/serving/config/SpecServiceConfig.java +++ b/serving/src/main/java/feast/serving/config/SpecServiceConfig.java @@ -37,12 +37,13 @@ public class SpecServiceConfig { private static final Logger log = org.slf4j.LoggerFactory.getLogger(SpecServiceConfig.class); private String feastCoreHost; private int feastCorePort; - private static final int CACHE_REFRESH_RATE_SECONDS = 10; + private int CACHE_REFRESH_RATE_SECONDS; @Autowired public SpecServiceConfig(FeastProperties feastProperties) { feastCoreHost = feastProperties.getCoreHost(); feastCorePort = feastProperties.getCoreGrpcPort(); + CACHE_REFRESH_RATE_SECONDS = feastProperties.getCoreCacheRefreshInterval(); } @Bean diff --git a/serving/src/main/resources/application.yml b/serving/src/main/resources/application.yml index 734f7b0096..16837b4608 100644 --- a/serving/src/main/resources/application.yml +++ b/serving/src/main/resources/application.yml @@ -17,6 +17,7 @@ feast: audience: https://localhost #token audience. jwkEndpointURI: #jwk enpoint uri, used for caching token till expiry. + core-cache-refresh-interval: 10 # Indicates the active store. Only a single store in the last can be active at one time. In the future this key # will be deprecated in order to allow multiple stores to be served from a single serving instance diff --git a/serving/src/test/java/feast/serving/it/ServingServiceIT.java b/serving/src/test/java/feast/serving/it/ServingServiceIT.java index 428dd598b9..f08ff88055 100644 --- a/serving/src/test/java/feast/serving/it/ServingServiceIT.java +++ b/serving/src/test/java/feast/serving/it/ServingServiceIT.java @@ -60,7 +60,11 @@ import org.testcontainers.junit.jupiter.Testcontainers; @ActiveProfiles("it") -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { + "feast.core-cache-refresh-interval=1", + }) @Testcontainers public class ServingServiceIT extends BaseAuthIT { @@ -441,9 +445,9 @@ public void shouldReturnNotFoundForUpdatedType() { TestUtils.applyFeatureTable( coreClient, projectName, featureTableName, entities, features, 7200); - // Sleep is necessary to ensure caching (every 10s) of updated FeatureTable is done + // Sleep is necessary to ensure caching (every 1s) of updated FeatureTable is done try { - Thread.sleep(15000); + Thread.sleep(2000); } catch (InterruptedException e) { } From 2c608eaba7339c83dbc4e6e453d5840740ef328c Mon Sep 17 00:00:00 2001 From: Terence Date: Mon, 2 Nov 2020 15:35:35 +0800 Subject: [PATCH 3/3] Update refresh interval name Signed-off-by: Terence --- .../java/feast/serving/config/SpecServiceConfig.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/serving/src/main/java/feast/serving/config/SpecServiceConfig.java b/serving/src/main/java/feast/serving/config/SpecServiceConfig.java index 32dbcec77c..b41a0f534a 100644 --- a/serving/src/main/java/feast/serving/config/SpecServiceConfig.java +++ b/serving/src/main/java/feast/serving/config/SpecServiceConfig.java @@ -37,13 +37,13 @@ public class SpecServiceConfig { private static final Logger log = org.slf4j.LoggerFactory.getLogger(SpecServiceConfig.class); private String feastCoreHost; private int feastCorePort; - private int CACHE_REFRESH_RATE_SECONDS; + private int feastCachedSpecServiceRefreshInterval; @Autowired public SpecServiceConfig(FeastProperties feastProperties) { - feastCoreHost = feastProperties.getCoreHost(); - feastCorePort = feastProperties.getCoreGrpcPort(); - CACHE_REFRESH_RATE_SECONDS = feastProperties.getCoreCacheRefreshInterval(); + this.feastCoreHost = feastProperties.getCoreHost(); + this.feastCorePort = feastProperties.getCoreGrpcPort(); + this.feastCachedSpecServiceRefreshInterval = feastProperties.getCoreCacheRefreshInterval(); } @Bean @@ -54,8 +54,8 @@ public ScheduledExecutorService cachedSpecServiceScheduledExecutorService( // reload all specs including new ones periodically scheduledExecutorService.scheduleAtFixedRate( cachedSpecStorage::scheduledPopulateCache, - CACHE_REFRESH_RATE_SECONDS, - CACHE_REFRESH_RATE_SECONDS, + feastCachedSpecServiceRefreshInterval, + feastCachedSpecServiceRefreshInterval, TimeUnit.SECONDS); return scheduledExecutorService; }