Code Monkey home page Code Monkey logo

grpc-spring-boot-starter's People

Contributors

a-gaitian avatar aaabramov avatar afurer avatar aglophotis avatar cleverunderdog avatar dadadom avatar dounan avatar imyxiao avatar jgleitz avatar joholland avatar jorgheymans avatar jvmlet avatar mchernyakov avatar nsobadzhiev avatar pink-lucifer avatar robertoduessmann avatar sarrruman avatar shina-blueprint avatar sineaggi avatar skjolber avatar tsonglew avatar willtaylor avatar yu-shiba avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grpc-spring-boot-starter's Issues

Support Spring Security @Secured annotation

Annotating a server implementation method with @Secured annotation currently doesn't have any effect.
It would be nice if the @Secured annotation is supported and a Status.PERMISSION_DENIED error is sent if the Authentication doesn't contain the proper authority.

@Component
public class AuthenticationInterceptor implements ServerInterceptor {
    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
        Authentication authentication = new UsernamePasswordAuthenticationToken("user", "user",
            Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER));
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return serverCallHandler.startCall(serverCall, metadata);  
    }
}
@GRpcService(interceptors = { LogInterceptor.class, AuthenticationInterceptor.class })
public class GreeterService extends GreeterGrpc.GreeterImplBase {
    @Override
    @Secured({ "ROLE_ADMIN" })
    public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver<GreeterOuterClass.HelloReply> responseObserver) {
        String message = "Hello " + request.getName();
        final GreeterOuterClass.HelloReply.Builder replyBuilder = GreeterOuterClass.HelloReply.newBuilder().setMessage(message);
        responseObserver.onNext(replyBuilder.build());
        responseObserver.onCompleted();
        log.info("Returning " +message);
    }
}

then stub.sayHello should fail with Status.PERMISSION_DENIED

can not access context's variables

Hello,

I have MyAuthInterceptor.class to put an identity into the context, and I want to access the identity from the context. Here UserMe identity = MyAuthInterceptor.USER_IDENTITY.get(); got error, refer to below code and error message:

@GRpcService(interceptors = {MyAuthInterceptor.class, LogInterceptor.class})
public class MyWordService extends MyWordGrpc.MyWordImplBase {
    private final static Gson gson = new Gson();
    private static final Logger logger = Logger.getLogger(MyWordService.class.getName());

    @Autowired
    private UserWordRepository userWordRepository;

    @Override
    public void list(ListRequest request, StreamObserver<MyWordResponse> responseObserver) {
        // Access to identity.
        UserMe identity = MyAuthInterceptor.USER_IDENTITY.get();


        logger.info(String.format("list start identity=%s, request=[%s]", identity, gson.toJson(request)));

}

/** Interceptor that validates user's identity. */
class MyAuthInterceptor implements ServerInterceptor {
  public static final Context.Key<UserMe> USER_IDENTITY
      = Context.key("identity"); // "identity" is just for debugging
 
  @Override 
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> call,
      Metadata headers,
      ServerCallHandler<ReqT, RespT> next) {
    // You need to implement validateIdentity 
    UserMe identity = validateIdentity(headers);
    if (identity == null) { // this is optional, depending on your needs
      // Assume user not authenticated 
      call.close(Status.UNAUTHENTICATED.withDescription("some more info"),
                 new Metadata());
      return new ServerCall.Listener() {}; 
    } 
    Context context = Context.current().withValue(USER_IDENTITY, identity);
    return Contexts.interceptCall(context, call, headers, next);
  }

  private UserMe validateIdentity(Metadata headers) {
    return new UserMe("conan");
  }
} 

java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:735) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:716) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:703) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:304) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
at org.ditto.easyhan.ApplicationSpringBoot.main(ApplicationSpringBoot.java:72) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Failed to create interceptor instance.; nested exception is java.lang.IllegalAccessException: Class org.lognet.springboot.grpc.GRpcServerRunner can not access a member of class org.ditto.easyhan.grpc.MyAuthInterceptor with modifiers ""
at org.lognet.springboot.grpc.GRpcServerRunner.lambda$bindInterceptors$2(GRpcServerRunner.java:110) ~[grpc-spring-boot-starter-2.1.0.jar:na]
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_121]
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948) ~[na:1.8.0_121]
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_121]
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_121]
at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312) ~[na:1.8.0_121]
at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743) ~[na:1.8.0_121]
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_121]
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_121]
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_121]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_121]
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_121]
at org.lognet.springboot.grpc.GRpcServerRunner.bindInterceptors(GRpcServerRunner.java:118) ~[grpc-spring-boot-starter-2.1.0.jar:na]
at org.lognet.springboot.grpc.GRpcServerRunner.lambda$run$1(GRpcServerRunner.java:82) ~[grpc-spring-boot-starter-2.1.0.jar:na]
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:1.8.0_121]
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[na:1.8.0_121]
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948) ~[na:1.8.0_121]
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_121]
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_121]
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:1.8.0_121]
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:1.8.0_121]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_121]
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[na:1.8.0_121]
at org.lognet.springboot.grpc.GRpcServerRunner.run(GRpcServerRunner.java:78) ~[grpc-spring-boot-starter-2.1.0.jar:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:732) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
... 6 common frames omitted
Caused by: java.lang.IllegalAccessException: Class org.lognet.springboot.grpc.GRpcServerRunner can not access a member of class org.ditto.easyhan.grpc.MyAuthInterceptor with modifiers ""
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102) ~[na:1.8.0_121]
at java.lang.Class.newInstance(Class.java:436) ~[na:1.8.0_121]
at org.lognet.springboot.grpc.GRpcServerRunner.lambda$bindInterceptors$2(GRpcServerRunner.java:108) ~[grpc-spring-boot-starter-2.1.0.jar:na]
... 30 common frames omitted

Update Gradle to version 4+

Current Gradle version being used in the project, 2.14.1, is falling behind quite a bit. I suggest that Gradle be updated to 4.6, which is the current version.

Accessing Metadata in @GRpcService

Before I invoke RPC, I attach CallCredentials to my stub, so I can know who the current user is:

// PersonContext.java
Long personId;
String username;

// GrpcSender.java
ManagedChannel channel = ManagedChannelBuilder.forAddress( "127.0.0.1", 6565 )
  .usePlaintext( true )
  .build();

HasPermissionServiceFutureStub stub = HasPermissionServiceGrpc.newFutureStub( channel )
  .withCallCredentials( new PersonContextCallCredentials( personContext ) );

stub.invoke( Pojo.newBuilder().setPersonId( 1L ).build() );

Is there a way I can access the CallCredentials metadata in my @GRpcService so I can verify that the personId in the metadata is equal to the personId in the Request Message POJO?

Alternatively, is there a way to access the Request Message POJO in my interceptor. Ideally, I'd do something like the following in my interceptCall method:

@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
  ServerCall<ReqT, RespT> call,
  Metadata headers,
  ServerCallHandler<ReqT, RespT> next )
{
  String currentPersonId = headers.get( PersonContextCallCredentials.METADATA_KEY_FOR_PERSON_ID );

  String requestedPersonId = REQUEST_MESSAGE_POJO.getPersonId();

  if ( currentPersonId != null && !currentPersonId.equals( requestedPersonId ) )
  {
    call.close( Status.PERMISSION_DENIED, new Metadata() );
  }

  return next.startCall( call, headers );
}

But I'm not sure how to access REQUEST_MESSAGE_POJO.

Add autoconfiguration support for distributed tracing

There is an issue on the spring-cloud-sleuth project that might be better addressed in this library. Now that spring-cloud-sleuth 2.x is using the brave tracing library, there are client/server interceptors for instrumenting gRPC calls. Since your project already has a concept of global, server-side interceptors via @GRpcGlobalInterceptor, I think it would be possible to add auto-configuration to setup up the tracing.

For server-side interceptor:

  • @ConditionalOnClass(GrpcTracing.class)
  • Write a custom Conditional that evaluates to true if you have at least one bean with the @GRpcService.

For client-side interceptor:

  • @ConditionalOnClass(GrpcTracing.class)
  • Put the client-side interceptor into the context.
  • An interesting idea would be to also put a ManagedChannelBuilder into the context @ConditionalOnMissingBean that could then be configured to use the client-side interceptor. Then a client can just inject the builder and use that to create the managed channel.

I have created a sample project that demonstrates spring-cloud-sleuth with grpc-spring-starter.

Update to proto 3.0.0

First, thanks for your efforts to develop gRPC support for Spring Boot. We are using both frameworks and think it is a good combination.

Are there any known issues running against the latest gRPC build? I see that protobuf 3.0.0 is now out and that there have been some recent dependency updates in the gRPC repository.

We plan on using grpc-spring-boot-starter with Gradle and are interested about your future plans. As we move forward we are happy to submit pull requests for any issues or improvements.

Best Regards,
David

Joining effort, integrate into Spring Boot Starter?

Hiya!

I just discovered this independently from something I was working on. Would you be interested in getting similar functionalities into the main spring boot starters?

A few minor differences:

  • No Java 8 dependence
  • Configurable discovery mechanism
  • Focused on the server side, we can have a separate grpc-client starter
  • Preconfigured Maven plugin

The last one is big for Maven users, where the getting started experience, with stub generation, will become super easy when using the preconfigured plugin from the parent POM.

spring-projects/spring-boot#5206

Thanks!

Integration test encounter port already in binding error.

Hi, thanks for your great starter.
It runs all OK except when I run integration test. With junit annotation like @RunWith(SpringRunner.class) @SpringBootTest, it will create an grpc-spring-boot-starter instance together with application instance for each test case, meanwhile they all share the same port, which is 6565 by default. So I encounter this exceptions:


Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189)
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:377)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
	at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Failed to execute CommandLineRunner
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:803)
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:784)
	at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:771)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:111)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
	... 45 more
Caused by: java.io.IOException: Failed to bind
	at io.grpc.netty.NettyServer.start(NettyServer.java:158)
	at io.grpc.internal.ServerImpl.start(ServerImpl.java:161)
	at io.grpc.internal.ServerImpl.start(ServerImpl.java:83)
	at org.lognet.springboot.grpc.GRpcServerRunner.run(GRpcServerRunner.java:67)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800)
	... 51 more
Caused by: java.net.BindException: Address already in use: bind
	at sun.nio.ch.Net.bind0(Native Method)
	at sun.nio.ch.Net.bind(Net.java:433)
	at sun.nio.ch.Net.bind(Net.java:425)
	at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
	at io.netty.channel.socket.nio.NioServerSocketChannel.doBind(NioServerSocketChannel.java:128)
	at io.netty.channel.AbstractChannel$AbstractUnsafe.bind(AbstractChannel.java:554)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.bind(DefaultChannelPipeline.java:1258)
	at io.netty.channel.AbstractChannelHandlerContext.invokeBind(AbstractChannelHandlerContext.java:502)
	at io.netty.channel.AbstractChannelHandlerContext.bind(AbstractChannelHandlerContext.java:487)
	at io.netty.channel.DefaultChannelPipeline.bind(DefaultChannelPipeline.java:980)
	at io.netty.channel.AbstractChannel.bind(AbstractChannel.java:250)
	at io.netty.bootstrap.AbstractBootstrap$2.run(AbstractBootstrap.java:365)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:403)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:445)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
	... 1 more


So, is there any advice to avoid this?

Please update gRPC

You're doing this for free of course, so I'm definitely not complaining, but it would be pretty fantastic if we could count on this repository to be updated more quickly.

Testing non-blocking bidirectional transfer

First of all, great job on the starter it is really light-weight and easy to use.

In your examples you have unary services only. I am using bidirectional services. Reading the gRPC documentation and recommendation they recommend using an InProcessServerBuilder for testing. However, I could not find a way to do this with the current setup. What do you propose I should do for something like this?

not found variable log?

just download the source code and import into intellij idea 2017.2, get the compiler complain:
Error:(49, 9) java: 找不到符号
符号: 变量 log
位置: 类 org.lognet.springboot.grpc.GRpcServerRunner

line 49: log.info("Starting gRPC Server ...");

Allow to use Reactor Flux or RxJava Observable instead of gRPC StreamObserver

Allow to use Reactive types like Reactor Flux or RxJava Observable instead of dealing direction with gRPC StreamObserver would be awesome for the end user, and since gRPC supports Backpressure that would be a very good match.

Integration with single value types like Reactor Mono or RxJava Single would also be really useful.

Maybe @saturnism has some ideas about how to achieve this since this is one of the topic or his upcoming Spring I/O talk ...

Configurable server

Hi,

Thanks for this project. It's a great example. I'm trying to use it and the server configuration is too limited (e.g., no TLS). From the variety of examples in Google, it seems that it is not likely that all solutions could be covered using a general properties file. Therefore I would suggest using a bean for the ServerBuilder. Idea is that application would provide with the end point configured. You could then add to it the discovered services and their interceptors. The current code would be changed to locate the bean from the ApplicationContext. If the bean can't be retrieved, then the code would instantiate one using the current port configuration capability. What do you think?

Cheers, Pierre

Use "compileOnly" configuration from gradle 2.13

Motivation:

  • gradle 2.13 introduced "compileOnly" for compiletime-only dependencies.

Change:

  • remove springframework-propdeps plugin
  • use compileOnly for "provided" and "optional" dependencies

Result:

  • One less gradle plugin needed / more standard features in use

Configure bind address

Hello,

I would like to be able to bind my gRPC on a dedicated interface.
It seems this is not possible:

  • This starter's configuration exposes only a port not an address.
  • Extending GRpcServerBuilderConfigurer gives access to an already created NettyServerBuilder
    and therefore the address property cannot be changed.

I am new to Spring and to this gRPC starter, so I'm wondering if maybe I have missed something obvious?
The current workaround would be to let the app bind on 0.0.0.0 and rely on a properly configured firewall. I would rather have the app bind to the expected interface.

Thanks,

Wildcard imports in Java are bad practice

In GRpcServerRunner.java you use wildcard imports for io.grpc.* and java.util.*.

While these seem very convenient, they are very problematic and are considered bad practice.
You may want to consider changing those to explicit imports. This is a really simple task with any modern Java IDE which can easily support you with imports.

As reference, please take a look at this SO question/answer: https://stackoverflow.com/questions/147454/why-is-using-a-wild-card-with-a-java-import-statement-bad

Is there a way to intercept RuntimeException ?

In gRPC , how to add a global exception interceptor that intercepts any RuntimeException and propagate meaningful information to the client ?

for example , a divide method may throw ArithmeticException with / by zero message . In the server side , I may write :

@Override
public void divide(DivideRequest request, StreamObserver<DivideResponse> responseObserver) {
  int dom = request.getDenominator();
  int num = request.getNumerator();

  double result = num / dom;
  responseObserver.onNext(DivideResponse.newBuilder().setValue(result).build());
  responseObserver.onCompleted();
}

If the client passes denominator = 0 , it will get :

Exception in thread "main" io.grpc.StatusRuntimeException: UNKNOWN
And the server outputs

Exception while executing runnable io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2@62e95ade
java.lang.ArithmeticException: / by zero

The client doesn't know what's going on.

If I want to pass / by zero message to client , I have to modify server to :

try {
    double result = num / dom;
    responseObserver.onNext(DivideResponse.newBuilder().setValue(result).build());
    responseObserver.onCompleted();
  } catch (Exception e) {
    logger.error("onError : {}" , e.getMessage());
    responseObserver.onError(new StatusRuntimeException(Status.INTERNAL.withDescription(e.getMessage())));
  }

And if client sends denominator = 0 , it will get :

Exception in thread "main" io.grpc.StatusRuntimeException: INTERNAL: / by zero

Good , / by zero is passed to client.

But the problem is , in a truly enterprise environment, there will be a lot of RuntimeExceptions , and if I want to pass these exception's messages to client , I will have to try catch each method , which is very cumbersome.

Is there any global interceptor that intercepts every method , catching RuntimeException and trigger onError and propagate the error message to client ? So that I don't have to deal with RuntimeExceptions in my server code .

I try to do like this :

@GRpcGlobalInterceptor
public class MyInterceptor implements ServerInterceptor {

  private Logger logger = LoggerFactory.getLogger(getClass());

  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
                                                               Metadata headers,
                                                               ServerCallHandler<ReqT, RespT> next) {
    logger.info("intercept {}", call.getMethodDescriptor().getFullMethodName());
    try {
      return next.startCall(call, headers);
    } catch (Throwable e) {
      logger.error("Throwable : {}" , e.getMessage());
      Status status = Status.INTERNAL.withDescription(e.getMessage());
      // then ?
      return ???
    }
  }
}

But it seems it cannot catch the Throwable when I pass denominator = 0 .

I am stuck here ...

Any hints ?

Thanks

Facing issue while running GRPC in embedded mode

I am trying to deploy my application [ GRPC + Spring Boot ] in Kubernetes infra.

I have set up a GRPC server with Spring boot on our pods - and as suggested I am running the processes on 2 different ports [ GRPC (port - 8443)+ Spring Boot (port- 8080) ] but my VIP is pointing to port 8443 right now.

I am able to configure SSL using .useTransportSecurity in a standalone grpc server (standalone here I mean without spring boot)

Problem: If my VIP is pointing to the GRPC server process on the pods I need to offload SSL in GRPC server but I do not see details how to do that if I am running my grpc server as an embedded server with spring boot.

Even if I deploy the application and when I try to connect using GRPC client I am seeing below error in servers and clinet is getting disconnected.

Where can I find additional application.properties specific to grpc ? I could only find grpc.server.port, grpc.server.host

2017-05-29 10:11:30.549 INFO 12796 --- [ main] n.d.s.a.grpc.server.GrpcServerLifecycle : gRPC Server started, listening on address: 0.0.0.0, port: 8443
2017-05-29 10:11:30.971 INFO 12796 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (https)
2017-05-29 10:11:30.979 INFO 12796 --- [ main] c.a.IntentProcessorGroup1Application : Started IntentProcessorGroup1Application in 26.45 seconds (JVM running for 27.737)
2017-05-29 10:11:41.736 WARN 12796 --- [-worker-ELG-3-1] io.grpc.netty.NettyServerHandler : Connection Error
io.netty.handler.codec.http2.Http2Exception: HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 160301008e0100008a03039bda7533eee4bee56f87bd4a42
at io.netty.handler.codec.http2.Http2Exception.connectionError(Http2Exception.java:85) ~[netty-codec-http2-4.1.8.Final.jar:4.1.8.Final]

Allow random port selection

In order to test several gRPC components with each other, I have several Spring Boot projects with this starter. I need to ensure that I always set the grpc.port property to something unused whenever I create a new project.

Would it be possible to allow random port selection when specifying grpc.port = 0, like it is e.g. done for server.port to allow random ports for the embedded Tomcat/Jetty server?

I can only imagine that the service discovery example is then a bit more tricky.

SpringMvc integration

For existing Code Base and smooth integration it would be if advance when server side code first contract API can still be specified with/rebase on spring MVC anotations. Why not create proto files for clientd based on spring MVC enpoints an allow grpc server listen and converts spring MVC endpoints on server side without additional coding effort based on existing spring MVC projects.
Most advanced the grpc server runs besides existing SpringMvc servlet.

HealthCheck

Greetings, thanks for the great contribution firstly, just wondering if possible to integrate with HealthStatusManager as part of the starter, and probably as well as consul(consul-template)/ or haproxy be part of the service discovery, governance utilities?

found ideas as this one: http://www.juhonkoti.net/2015/11/26/using-haproxy-to-do-health-checks-to-grpc-services

@GRpcService(grpcServiceOuterClass = HealthCheckServiceGrpc.class, serviceName = "HealthCheckGRpcService")
public class HealthCheckGRpcService extends HealthCheckServiceGrpc.HealthCheckServiceImplBase{

@Autowired
private HealthStatusManager healthStatusManager;

@Override
public void status(Health.StatusRequest request, StreamObserver<Health.HealthCheckResult> responseObserver) {
    Health.HealthCheckResult.Builder builder = Health.HealthCheckResult.newBuilder();
    builder.setStatus("1");
    responseObserver.onNext(builder.build());
    responseObserver.onCompleted();
}

@PostConstruct
public void healthInit(){
    healthStatusManager.setStatus(this.getClass().getName(), HealthCheckResponse.ServingStatus.SERVING);
}

@PreDestroy
public void healthDestroy(){
    healthStatusManager.clearStatus(this.getClass().getName());
}

}

Add gradle wrapper

Motivation:
Simplify building of project

Change:
Add gradle 2.11 as wrapper and use it on travis.

Result:
We have control over the gradle version in use and make it easier to execute the build. We can upgrade to gradle 2.13 once we have upgraded the plugins as com.google.protobuf plugin currently in use is incompatible with gradle 2.13.

@GRpcGlobalInterceptor beans, created by @Bean inside @Configuration, are ignored if there is a class with annotation @GRpcGlobalInterceptor

Spring Boot Version: 2.0.0.RELEASE

@GRpcGlobalInterceptor beans, created by @Bean inside @Configuration, are ignored if there is a class with annotation @GRpcGlobalInterceptor

Example:

@GRpcGlobalInterceptor
class ComponentInterceptor implements ServerInterceptor {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        System.out.println("ComponentInterceptor");
        return next.startCall(call, headers);
    }
}

class FactoryBeanInterceptor implements ServerInterceptor {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        System.out.println("FactoryBeanInterceptor");
        return next.startCall(call, headers);
    }
}

@Configuration
class GrpcConfiguration {

    @Bean
    @GRpcGlobalInterceptor
    FactoryBeanInterceptor factoryBeanInterceptor() {
        return new FactoryBeanInterceptor();
    }

}

If we run an app, only ComponentInterceptor will be executed.

No Support for Maven builds

While I understand and appreciate your personal preference for Gradle, there are plenty of developers out that that use Maven for various good reasons.

Each and every Spring-related project should also have a Maven pom.xml included in it.

grpc services and @Transactional

Hi,

It seems that spring's @transactional has no effect when used in a @GrpcService class. This is probably expected but nevertheless surprising. Integrating with spring's tx interceptor mechanics could make a worthy addition to this starter.

(and no i don't have a PR ready)

build polishing

Hi,

I'd like to contribute to this project. Based on my first glance I would have a few build improvements that come to my mind. Please give some feedback on how you like to see contributions (e.g. create / discuss issues first, only one issue per PR... etc)

  • add gradle wrapper
  • use "compileOnly" configuration from gradle 2.13
  • upgrade dependencies (spring-boot, grpc, spring-cloud, lombok)
  • missing .gitignore
  • do you really want to check-in the generated code (grpc-spring-boot-starter-demo/src/protoGen/)

gradle build exception

exception
➜ grpc-spring-boot-starter git:(master) gradle build --info
Starting Build
Settings evaluated using settings file '/Users/leo/Documents/git/grpc-spring-boot-starter/settings.gradle'.
Projects loaded. Root project using build file '/Users/leo/Documents/git/grpc-spring-boot-starter/build.gradle'.
Included projects: [root project 'org.lognet', project ':grpc-spring-boot-starter', project ':grpc-spring-boot-starter-demo']
Evaluating root project 'org.lognet' using build file '/Users/leo/Documents/git/grpc-spring-boot-starter/build.gradle'.

FAILURE: Build failed with an exception.

  • Where:
    Build file '/Users/leo/Documents/git/grpc-spring-boot-starter/build.gradle' line: 45

  • What went wrong:
    A problem occurred evaluating root project 'org.lognet'.

    Could not find method compileOnly() for arguments [org.projectlombok:lombok:1.16.6] on org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler_Decorated@61ff6a49.

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --debug option to get more log output.

BUILD FAILED

Total time: 3.334 secs
Stopped 0 compiler daemon(s).

better shutdown ?

I came across this on the grpc groups https://groups.google.com/d/msg/grpc-io/P5BFGoGxkbw/ozwwY9bDCQAJ and was wondering if GrpcServerRunner is doing enough by just calling shutdown

   @Override
   public void destroy() throws Exception {
       log.info("Shutting down gRPC server ...");
       server.getServices().forEach(def->healthStatusManager.clearStatus(def.getServiceDescriptor().getName()));
       Optional.ofNullable(server).ifPresent(Server::shutdown);
       log.info("gRPC server stopped.");
   }

From the post:

server.shutdown(); // This simply prevents new RPCs
server.awaitTermination(5, SECONDS); // This is the grace time
server.shutdownNow(); // This kills all RPCs
// This needs some time to queue cancellation notifications.
// Note that terminated does not imply the application is done processing.
// It only means the server won't issue any more work to the application.
if (!server.awaitTermination(1, SECONDS)) {
log.log(WARNING, "For some reason the server didn't shutdown promptly");
}
// After the server is terminated, all work has at least been queued onto the server's executor.
// You can shutdown and wait on that executor if you want. You can then also clean up services.
cleanUpServices();

@Bean interceptor not taken into account

Hi,

I have a @configuration class that defines a couple of @GlobalInterceptor classes like

  @GRpcGlobalInterceptor
  static class SSLSessionInterceptor implements ServerInterceptor {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata headers,
        ServerCallHandler<ReqT, RespT> next) {
      // ..............
  }

I then added another one using the @bean style configuration (according to the documentation this is supported)

  @Bean
  public ServerInterceptor beanInterceptor() {
    return new ServerInterceptor() {
      @Override
      public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata,
          ServerCallHandler<ReqT, RespT> serverCallHandler) {
        System.out.println("#########################");
        return serverCallHandler.startCall(serverCall, metadata);
      }
    };
  }

But this last interceptor is never called, I am assuming it does not get registered correctly on the GrpcServer. Anyone else seen this ?

NPE thrown when trying to discover annotations on AOP Proxy objects

In version 0.0.6, the org.lognet.springboot.grpc.GRpcServerRunner#run method tries to discover the @GRpcService annotation. However, this fails if the bindableService is wrapped as an AOP proxy.

A possible fix would be to check if the bindableService is a Proxy, and use its target class instead to find the @GRpcService annotation.

Using Spring 5 webflux with GRPC uses 2 different ports

Hey guys, first of all kudos for the great job you've done.
Actually, I'm trying to spin up a Spring Boot (2.0) Webflux server exposing some REST APIs through
netty. This works fine and now I would like to give an extra alternative adding gRPC to the game.
I've managed to expose it but via another port (8080 for REST API, 9090 for gRPC).
Maybe that's unfeasible since gRPC requires HTTP 2 and the REST APIs can work with HTTP 1, but would be great if both options share the same port.

README Google RPC -> gRPC

A quick note - gRPC is actually a recursive acronym. on the contrary it isn't Google RPC, it is actually gRPC Remote Procedure Call framework :)

Upgrade protobuf-gradle-plugin

Motivation:

  • com.google.protobuf plugin is incompatible with latest gradle
  • latest com.google.protobuf requires gradle 2.12+

Change:

  • upgrade protobuf plugin to 0.7.7
  • add gradle 2.13 as gradle wrapper

Result:

  • we are aligned with latest plugin and gradle releases

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.