Skip to content

Commit

Permalink
gRPC fix request context clean-up and classloaders after dev mode reload
Browse files Browse the repository at this point in the history
  • Loading branch information
michalszynkiewicz committed Apr 30, 2021
1 parent cfd5d98 commit 98e00c6
Show file tree
Hide file tree
Showing 24 changed files with 355 additions and 147 deletions.
9 changes: 7 additions & 2 deletions docs/src/main/asciidoc/grpc-service-implementation.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,16 @@ The second implementation base is: `MutinyGreeterGrpc.GreeterImplBase`.
Note that these classes are not interfaces but regular classes.
When extending them, you need to override the service methods defined in the service definition.

gRPC service implementations have to be annotated with `@GrpcService` annotation.

NOTE: gRPC services have to be CDI beans with `Singleton` scope. The `@GrpcService` annotation makes sure of that
and, additionally, makes sure that `RequestContext`, needed e.g. to make database calls, is enabled in your service.

== Implementing a service with the default gRPC API

To implement a gRPC service using the default gRPC API, create a class extending the default implementation base.
Then, override the methods defined in the service interface.
Finally, implement the service as a CDI bean using the `@GrpcService` annotation:
Finally, implement the service and add the `@GrpcService` annotation:

[source, java]
----
Expand All @@ -65,7 +70,7 @@ public class HelloService extends GreeterGrpc.GreeterImplBase {
To implement a gRPC service using the Mutiny gRPC API, create a class extending the Mutiny implementation base.
Then, override the methods defined in the service interface.
These methods are using Mutiny types.
Finally, implement the service as a CDI bean using the `@Singleton` annotation:
Finally, implement the service and add the `@GrpcService` annotation:

[source, java]
----
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.grpc.deployment;

import static io.quarkus.deployment.Feature.GRPC_SERVER;
import static io.quarkus.grpc.deployment.GrpcDotNames.GRPC_SERVICE;
import static java.util.Arrays.asList;

import java.lang.reflect.Modifier;
Expand All @@ -18,8 +19,8 @@
import io.grpc.BindableService;
import io.grpc.internal.ServerImpl;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
import io.quarkus.arc.deployment.ValidationPhaseBuildItem;
import io.quarkus.arc.deployment.ValidationPhaseBuildItem.ValidationErrorBuildItem;
import io.quarkus.arc.processor.BeanInfo;
import io.quarkus.arc.processor.BuiltinScope;
import io.quarkus.deployment.IsDevelopment;
Expand All @@ -44,6 +45,8 @@
import io.quarkus.grpc.runtime.config.GrpcServerBuildTimeConfig;
import io.quarkus.grpc.runtime.health.GrpcHealthEndpoint;
import io.quarkus.grpc.runtime.health.GrpcHealthStorage;
import io.quarkus.grpc.runtime.supports.context.GrpcEnableRequestContext;
import io.quarkus.grpc.runtime.supports.context.GrpcRequestContextCdiInterceptor;
import io.quarkus.kubernetes.spi.KubernetesPortBuildItem;
import io.quarkus.netty.deployment.MinNettyAllocatorMaxOrderBuildItem;
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
Expand All @@ -66,9 +69,11 @@ MinNettyAllocatorMaxOrderBuildItem setMinimalNettyMaxOrderSize() {

@BuildStep
void discoverBindableServices(BuildProducer<BindableServiceBuildItem> bindables,
CombinedIndexBuildItem combinedIndexBuildItem) {
CombinedIndexBuildItem combinedIndexBuildItem,
BuildProducer<AnnotationsTransformerBuildItem> annotationTransformers) {
Collection<ClassInfo> bindableServices = combinedIndexBuildItem.getIndex()
.getAllKnownImplementors(GrpcDotNames.BINDABLE_SERVICE);

for (ClassInfo service : bindableServices) {
if (Modifier.isAbstract(service.flags())) {
continue;
Expand All @@ -85,10 +90,16 @@ void discoverBindableServices(BuildProducer<BindableServiceBuildItem> bindables,

@BuildStep
void validateBindableServices(ValidationPhaseBuildItem validationPhase,
BuildProducer<ValidationErrorBuildItem> errors) {
BuildProducer<ValidationPhaseBuildItem.ValidationErrorBuildItem> errors) {
for (BeanInfo bean : validationPhase.getContext().beans().classBeans().withBeanType(BindableService.class)) {
//noinspection OptionalGetWithoutIsPresent
if (bean.getTarget().get().asClass().classAnnotation(GRPC_SERVICE) == null) {
errors.produce(new ValidationPhaseBuildItem.ValidationErrorBuildItem(
new IllegalStateException(
"A gRPC service bean must be annotated with io.quarkus.GrpcService: " + bean)));
}
if (!bean.getScope().getDotName().equals(BuiltinScope.SINGLETON.getName())) {
errors.produce(new ValidationErrorBuildItem(
errors.produce(new ValidationPhaseBuildItem.ValidationErrorBuildItem(
new IllegalStateException("A gRPC service bean must have the javax.inject.Singleton scope: " + bean)));
}
}
Expand All @@ -109,6 +120,8 @@ void registerBeans(BuildProducer<AdditionalBeanBuildItem> beans,
List<BindableServiceBuildItem> bindables, BuildProducer<FeatureBuildItem> features) {
// @GrpcService is a CDI stereotype
beans.produce(new AdditionalBeanBuildItem(GrpcService.class));
beans.produce(new AdditionalBeanBuildItem(GrpcRequestContextCdiInterceptor.class));
beans.produce(new AdditionalBeanBuildItem(GrpcEnableRequestContext.class));
if (!bindables.isEmpty()) {
beans.produce(AdditionalBeanBuildItem.unremovableOf(GrpcContainer.class));
features.produce(new FeatureBuildItem(GRPC_SERVER));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package io.quarkus.grpc.client.tls;

import javax.inject.Singleton;

import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.examples.helloworld.MutinyGreeterGrpc;
import io.quarkus.grpc.GrpcService;
import io.smallrye.mutiny.Uni;

@Singleton
@GrpcService
public class HelloWorldTlsService extends MutinyGreeterGrpc.GreeterImplBase {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import java.util.Arrays;
import java.util.List;

import javax.inject.Singleton;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.AfterEach;
Expand All @@ -34,6 +32,7 @@
import io.grpc.reflection.v1alpha.ServerReflectionResponse;
import io.grpc.reflection.v1alpha.ServiceResponse;
import io.quarkus.grpc.GrpcClient;
import io.quarkus.grpc.GrpcService;
import io.quarkus.test.QuarkusUnitTest;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
Expand Down Expand Up @@ -279,7 +278,7 @@ public void cancel() {
}
}

@Singleton
@GrpcService
public static class MyReflectionService extends MutinyReflectableServiceGrpc.ReflectableServiceImplBase {
@Override
public Uni<Reply> method(Request request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Singleton;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
Expand All @@ -16,6 +15,7 @@

import io.grpc.BindableService;
import io.grpc.ServerServiceDefinition;
import io.quarkus.grpc.GrpcService;
import io.quarkus.grpc.runtime.GrpcServerRecorder;
import io.quarkus.test.QuarkusUnitTest;

Expand All @@ -39,7 +39,7 @@ public void test() {
assertThat(GrpcServerRecorder.getVerticleCount()).isGreaterThan(0);
}

@Singleton
@GrpcService
static class MyFakeService implements BindableService {

@Override
Expand All @@ -48,7 +48,7 @@ public ServerServiceDefinition bindService() {
}
}

@Singleton
@GrpcService
static class MySecondFakeService implements BindableService {

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package io.quarkus.grpc.server.devmode;

import javax.inject.Singleton;
import javax.enterprise.context.RequestScoped;

import devmodetest.v1.Devmodetest;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.stub.StreamObserver;
import io.quarkus.arc.Arc;
import io.quarkus.grpc.GrpcService;

@Singleton
@GrpcService
public class DevModeTestService extends GreeterGrpc.GreeterImplBase {

@Override
Expand All @@ -20,7 +22,11 @@ public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseOb
} else {
response = greeting + request.getName();
}
responseObserver.onNext(HelloReply.newBuilder().setMessage(response).build());
if (Arc.container().getActiveContext(RequestScoped.class) != null) {
responseObserver.onNext(HelloReply.newBuilder().setMessage(response).build());
} else {
throw new IllegalStateException("request context not active, failing");
}
responseObserver.onCompleted();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

import java.time.Duration;

import javax.inject.Singleton;

import com.example.test.MutinyStreamsGrpc;
import com.example.test.StreamsOuterClass.Item;

import io.quarkus.grpc.GrpcService;
import io.smallrye.mutiny.Multi;

@Singleton
@GrpcService
public class DevModeTestStreamService extends MutinyStreamsGrpc.StreamsImplBase {

public static final String PREFIX = "echo::";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package io.quarkus.grpc.server.scaling;

import javax.inject.Singleton;

import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.stub.StreamObserver;
import io.quarkus.grpc.GrpcService;

@Singleton
@GrpcService
public class ThreadReturningGreeterService extends GreeterGrpc.GreeterImplBase {

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package io.quarkus.grpc.server.services;

import javax.inject.Singleton;

import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
Expand All @@ -10,9 +8,10 @@
import io.grpc.examples.helloworld3.HelloRequest3;
import io.grpc.stub.StreamObserver;
import io.quarkus.grpc.GrpcClient;
import io.quarkus.grpc.GrpcService;
import io.smallrye.common.annotation.Blocking;

@Singleton
@GrpcService
public class GrpcCallWithinBlockingService extends Greeter3Grpc.Greeter3ImplBase {

@GrpcClient
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package io.quarkus.grpc.server.services;

import javax.inject.Singleton;

import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.examples.helloworld.MutinyGreeterGrpc;
import io.quarkus.grpc.GrpcService;
import io.smallrye.mutiny.Uni;

@Singleton
@GrpcService
public class MutinyHelloService extends MutinyGreeterGrpc.GreeterImplBase {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@

import java.util.concurrent.atomic.AtomicInteger;

import javax.inject.Singleton;

import com.google.protobuf.ByteString;
import com.google.protobuf.EmptyProtos;

import io.grpc.testing.integration.Messages;
import io.grpc.testing.integration.MutinyTestServiceGrpc;
import io.quarkus.grpc.GrpcService;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;

@Singleton
@GrpcService
public class MutinyTestService extends MutinyTestServiceGrpc.TestServiceImplBase {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

import javax.inject.Singleton;

import com.google.protobuf.ByteString;
import com.google.protobuf.EmptyProtos;

import io.grpc.stub.StreamObserver;
import io.grpc.testing.integration.Messages;
import io.grpc.testing.integration.TestServiceGrpc;
import io.quarkus.grpc.GrpcService;

@Singleton
@GrpcService
public class TestService extends TestServiceGrpc.TestServiceImplBase {

@Override
Expand Down Expand Up @@ -82,8 +81,6 @@ public void onCompleted() {
};
}

;

@Override
public StreamObserver<Messages.StreamingOutputCallRequest> fullDuplexCall(
StreamObserver<Messages.StreamingOutputCallResponse> responseObserver) {
Expand Down Expand Up @@ -122,6 +119,7 @@ public StreamObserver<Messages.StreamingOutputCallRequest> halfDuplexCall(
return new StreamObserver<Messages.StreamingOutputCallRequest>() {
@Override
public void onNext(Messages.StreamingOutputCallRequest streamingOutputCallRequest) {
assertThatTheRequestScopeIsActive();
String payload = streamingOutputCallRequest.getPayload().getBody().toStringUtf8();
ByteString value = ByteString.copyFromUtf8(payload.toUpperCase());
Messages.Payload response = Messages.Payload.newBuilder().setBody(value).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import javax.enterprise.inject.Stereotype;
import javax.inject.Singleton;

import io.quarkus.grpc.runtime.supports.context.GrpcEnableRequestContext;

/**
* Stereotype used to mark a gRPC service class.
*/
@Singleton
@GrpcEnableRequestContext
@Stereotype
@Target(TYPE)
@Retention(RetentionPolicy.RUNTIME)
Expand Down
Loading

0 comments on commit 98e00c6

Please sign in to comment.