Skip to content

Commit f2cd866

Browse files
vanitabhagwatvbhagwat
andauthored
feat: FeastClient factory methods for pre-configured stubs (#343)
* feat:FeastClient factory methods for pre-configured stubs * fix linting errors --------- Co-authored-by: vbhagwat <vbhagwat@expediagroup.com>
1 parent 7885de0 commit f2cd866

2 files changed

Lines changed: 181 additions & 5 deletions

File tree

java/serving-client/src/main/java/dev/feast/FeastClient.java

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,46 @@ public static FeastClient createSecure(
175175
nettyChannelBuilder.build(), securityConfig.getCredentials(), requestTimeout);
176176
}
177177

178+
/**
179+
* Create a client with a pre-configured stub.
180+
*
181+
* @param stub pre-configured {@link ServingServiceBlockingStub}
182+
* @param credentials optional {@link CallCredentials}
183+
* @param requestTimeout timeout in milliseconds, use 0 for no timeout
184+
* @return {@link FeastClient}
185+
*/
186+
public static FeastClient createWithStub(
187+
ServingServiceBlockingStub stub, Optional<CallCredentials> credentials, long requestTimeout) {
188+
if (requestTimeout < 0) {
189+
throw new IllegalArgumentException("Request timeout can't be negative");
190+
}
191+
return new FeastClient(stub, credentials, requestTimeout);
192+
}
193+
194+
/**
195+
* Create a client with a pre-configured stub.
196+
*
197+
* @param stub pre-configured {@link ServingServiceBlockingStub}
198+
* @param requestTimeout timeout in milliseconds, use 0 for no timeout
199+
* @return {@link FeastClient}
200+
*/
201+
public static FeastClient createWithStub(ServingServiceBlockingStub stub, long requestTimeout) {
202+
if (requestTimeout < 0) {
203+
throw new IllegalArgumentException("Request timeout can't be negative");
204+
}
205+
return new FeastClient(stub, Optional.empty(), requestTimeout);
206+
}
207+
208+
/**
209+
* Create a client with a pre-configured stub.
210+
*
211+
* @param stub pre-configured {@link ServingServiceBlockingStub}
212+
* @return {@link FeastClient}
213+
*/
214+
public static FeastClient createWithStub(ServingServiceBlockingStub stub) {
215+
return new FeastClient(stub, Optional.empty(), 0);
216+
}
217+
178218
/**
179219
* Obtain info about Feast Serving.
180220
*
@@ -599,13 +639,35 @@ protected FeastClient(ManagedChannel channel, Optional<CallCredentials> credenti
599639

600640
protected FeastClient(
601641
ManagedChannel channel, Optional<CallCredentials> credentials, long requestTimeout) {
602-
this.channel = channel;
642+
this(channel, null, credentials, requestTimeout);
643+
}
644+
645+
protected FeastClient(
646+
ServingServiceBlockingStub stub, Optional<CallCredentials> credentials, long requestTimeout) {
647+
this(null, stub, credentials, requestTimeout);
648+
}
649+
650+
private FeastClient(
651+
ManagedChannel channel,
652+
ServingServiceBlockingStub stub,
653+
Optional<CallCredentials> credentials,
654+
long requestTimeout) {
655+
603656
this.requestTimeout = requestTimeout;
604-
TracingClientInterceptor tracingInterceptor =
605-
TracingClientInterceptor.newBuilder().withTracer(GlobalTracer.get()).build();
657+
ServingServiceBlockingStub servingStub;
658+
659+
if (stub != null) {
660+
servingStub = stub;
661+
this.channel = null;
662+
} else if (channel != null) {
663+
this.channel = channel;
664+
TracingClientInterceptor tracingInterceptor =
665+
TracingClientInterceptor.newBuilder().withTracer(GlobalTracer.get()).build();
606666

607-
ServingServiceBlockingStub servingStub =
608-
ServingServiceGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
667+
servingStub = ServingServiceGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
668+
} else {
669+
throw new IllegalArgumentException("Either channel or stub must be provided");
670+
}
609671

610672
if (credentials.isPresent()) {
611673
servingStub = servingStub.withCallCredentials(credentials.get());

java/serving-client/src/test/java/dev/feast/FeastClientTest.java

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,120 @@ private void shouldGetOnlineFeaturesRangeWithClient(FeastClient client) {
390390
assertEquals(new HashMap<String, List<FieldStatus>>() {}, rows.get(0).getStatuses());
391391
}
392392

393+
@Test
394+
public void shouldCreateClientWithStub() throws Exception {
395+
String serverName = InProcessServerBuilder.generateName();
396+
this.grpcRule.register(
397+
InProcessServerBuilder.forName(serverName)
398+
.directExecutor()
399+
.addService(this.servingMock)
400+
.build()
401+
.start());
402+
403+
ManagedChannel channel =
404+
this.grpcRule.register(
405+
InProcessChannelBuilder.forName(serverName).directExecutor().build());
406+
407+
feast.proto.serving.ServingServiceGrpc.ServingServiceBlockingStub stub =
408+
feast.proto.serving.ServingServiceGrpc.newBlockingStub(channel);
409+
410+
FeastClient client = FeastClient.createWithStub(stub);
411+
shouldGetOnlineFeaturesFeatureRef(client);
412+
client.close();
413+
}
414+
415+
@Test
416+
public void shouldCreateClientWithStubAndTimeout() throws Exception {
417+
String serverName = InProcessServerBuilder.generateName();
418+
this.grpcRule.register(
419+
InProcessServerBuilder.forName(serverName)
420+
.directExecutor()
421+
.addService(this.servingMock)
422+
.build()
423+
.start());
424+
425+
ManagedChannel channel =
426+
this.grpcRule.register(
427+
InProcessChannelBuilder.forName(serverName).directExecutor().build());
428+
429+
feast.proto.serving.ServingServiceGrpc.ServingServiceBlockingStub stub =
430+
feast.proto.serving.ServingServiceGrpc.newBlockingStub(channel);
431+
432+
FeastClient client = FeastClient.createWithStub(stub, TIMEOUT_MILLIS);
433+
shouldGetOnlineFeaturesFeatureService(client);
434+
client.close();
435+
}
436+
437+
@Test
438+
public void shouldCreateClientWithStubAndCredentials() throws Exception {
439+
String serverName = InProcessServerBuilder.generateName();
440+
this.grpcRule.register(
441+
InProcessServerBuilder.forName(serverName)
442+
.directExecutor()
443+
.addService(this.servingMock)
444+
.build()
445+
.start());
446+
447+
ManagedChannel channel =
448+
this.grpcRule.register(
449+
InProcessChannelBuilder.forName(serverName).directExecutor().build());
450+
451+
feast.proto.serving.ServingServiceGrpc.ServingServiceBlockingStub stub =
452+
feast.proto.serving.ServingServiceGrpc.newBlockingStub(channel);
453+
454+
FeastClient client = FeastClient.createWithStub(stub, Optional.empty(), TIMEOUT_MILLIS);
455+
shouldGetOnlineFeaturesWithoutStatus(client);
456+
client.close();
457+
}
458+
459+
@Test
460+
public void shouldGetOnlineFeaturesRangeWithStub() throws Exception {
461+
String serverName = InProcessServerBuilder.generateName();
462+
this.grpcRule.register(
463+
InProcessServerBuilder.forName(serverName)
464+
.directExecutor()
465+
.addService(this.servingMock)
466+
.build()
467+
.start());
468+
469+
ManagedChannel channel =
470+
this.grpcRule.register(
471+
InProcessChannelBuilder.forName(serverName).directExecutor().build());
472+
473+
feast.proto.serving.ServingServiceGrpc.ServingServiceBlockingStub stub =
474+
feast.proto.serving.ServingServiceGrpc.newBlockingStub(channel);
475+
476+
FeastClient client = FeastClient.createWithStub(stub);
477+
shouldGetOnlineFeaturesRangeWithClient(client);
478+
client.close();
479+
}
480+
481+
@Test
482+
public void shouldThrowExceptionForNegativeTimeout() {
483+
String serverName = InProcessServerBuilder.generateName();
484+
try {
485+
this.grpcRule.register(
486+
InProcessServerBuilder.forName(serverName)
487+
.directExecutor()
488+
.addService(this.servingMock)
489+
.build()
490+
.start());
491+
492+
ManagedChannel channel =
493+
this.grpcRule.register(
494+
InProcessChannelBuilder.forName(serverName).directExecutor().build());
495+
496+
feast.proto.serving.ServingServiceGrpc.ServingServiceBlockingStub stub =
497+
feast.proto.serving.ServingServiceGrpc.newBlockingStub(channel);
498+
499+
IllegalArgumentException exception =
500+
assertThrows(IllegalArgumentException.class, () -> FeastClient.createWithStub(stub, -1));
501+
assertEquals("Request timeout can't be negative", exception.getMessage());
502+
} catch (Exception e) {
503+
throw new RuntimeException(e);
504+
}
505+
}
506+
393507
private static GetOnlineFeaturesRequest getFakeOnlineFeaturesRefRequest() {
394508
// setup mock serving service stub
395509
return GetOnlineFeaturesRequest.newBuilder()

0 commit comments

Comments
 (0)