Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add serving integration test for updated feature type #1112

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions serving/src/main/java/feast/serving/config/FeastProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 feastCachedSpecServiceRefreshInterval;

@Autowired
public SpecServiceConfig(FeastProperties feastProperties) {
feastCoreHost = feastProperties.getCoreHost();
feastCorePort = feastProperties.getCoreGrpcPort();
this.feastCoreHost = feastProperties.getCoreHost();
this.feastCorePort = feastProperties.getCoreGrpcPort();
this.feastCachedSpecServiceRefreshInterval = feastProperties.getCoreCacheRefreshInterval();
}

@Bean
Expand All @@ -53,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;
}
Expand Down
1 change: 1 addition & 0 deletions serving/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ feast:
audience: https://localhost #token audience.
jwkEndpointURI: <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
Expand Down
77 changes: 76 additions & 1 deletion serving/src/test/java/feast/serving/it/ServingServiceIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -419,4 +423,75 @@ public void shouldReturnNotFoundForDiffType() {

assertEquals(expectedFieldValuesList, featureResponse.getFieldValuesList());
}

@Test
public void shouldReturnNotFoundForUpdatedType() {
String projectName = "default";
String entityName = "driver_id";
String featureTableName = "rides";

ImmutableList<String> entities = ImmutableList.of(entityName);
ImmutableMap<String, ValueProto.ValueType.Enum> 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 1s) of updated FeatureTable is done
try {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to manually trigger cache invalidation?
or at least configure it to every second for example?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, we set the number of seconds here, I don't think it's possible to configure this setting.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but it can be moved to Spring config, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean make it configurable thru serving's application.yml?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep

Thread.sleep(2000);
} 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<GetOnlineFeaturesRequestV2.EntityRow> entityRows = ImmutableList.of(entityRow1);

// Instantiate FeatureReferences
ServingAPIProto.FeatureReferenceV2 featureReference =
DataGenerator.createFeatureReference("rides", "trip_distance");

ImmutableList<ServingAPIProto.FeatureReferenceV2> featureReferences =
ImmutableList.of(featureReference);

// Build GetOnlineFeaturesRequestV2
GetOnlineFeaturesRequestV2 onlineFeatureRequest =
TestUtils.createOnlineFeatureRequest(projectName, featureReferences, entityRows);
GetOnlineFeaturesResponse featureResponse =
servingStub.getOnlineFeaturesV2(onlineFeatureRequest);

ImmutableMap<String, ValueProto.Value> expectedValueMap =
ImmutableMap.of(
entityName,
entityValue,
FeatureV2.getFeatureStringRef(featureReference),
DataGenerator.createEmptyValue());

ImmutableMap<String, GetOnlineFeaturesResponse.FieldStatus> 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<GetOnlineFeaturesResponse.FieldValues> expectedFieldValuesList =
ImmutableList.of(expectedFieldValues);

assertEquals(expectedFieldValuesList, featureResponse.getFieldValuesList());
}
}