Skip to content

Commit

Permalink
Add autoconfiguration guard on GrpcServlet
Browse files Browse the repository at this point in the history
This commit adds a guard on the Servlet gRPC server auto-configuration
to ensure that the `io.grpc:grpc-servlet-jakarta` lib is on the classpath.

Resolves #83

Signed-off-by: Chris Bono <[email protected]>
  • Loading branch information
onobc committed Dec 20, 2024
1 parent 8628aa1 commit c52d6d8
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 43 deletions.
13 changes: 9 additions & 4 deletions spring-grpc-docs/src/main/antora/modules/ROOT/pages/server.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ dependencies {
== Servlet Server

Any servlet container can be used to run a gRPC server.
Spring gRPC includes autoconfiguration that configures the server to use the servlet container if it detects that it is in a web application, so all you have to do is include `spring-boot-starter-web` in your application.
Spring gRPC includes autoconfiguration that configures the server to use the servlet container if it detects that it is in a web application, so all you have to do is include `spring-boot-starter-web` and the `grpc-servlet` dependnecy in your application.

[source,xml]
----
Expand All @@ -71,19 +71,24 @@ Spring gRPC includes autoconfiguration that configures the server to use the ser
<groupId>org.springframework.grpc</groupId>
<artifactId>spring-grpc-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-servlet-jakarta</artifactId>
</dependency>
----

For Gradle users

[source,gradle]
----
dependencies {
implementation "org.springframework.boot:spring-boot-starter-web"
implementation "org.springframework.grpc:spring-grpc-spring-boot-starter"
implementation "org.springframework.boot:spring-boot-starter-web"
implementation "org.springframework.grpc:spring-grpc-spring-boot-starter"
implementation "io.grpc:grpc-servlet-jakarta"
}
----

The `spring.grpc.server.*` properties will be ignored in facour of the regular `server.*` properties in this case (with the exception of `spring.grpc.server.max-inbound-message-size`).
The `spring.grpc.server.*` properties will be ignored in favour of the regular `server.*` properties in this case (with the exception of `spring.grpc.server.max-inbound-message-size`).
The servlet that is created is mapped to process HTTP POST requests to the paths defined by the registered services, as `/<service-name>/*`.
Clients can connect to the server using that path, which is what any gRPC client library will do.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,47 @@
|Name | Default | Description

|spring.grpc.client.channels | |
|spring.grpc.client.default-channel.address | | The target address uri to connect to.
|spring.grpc.client.default-channel.default-load-balancing-policy | | The default load balancing policy the channel should use.
|spring.grpc.client.default-channel.enable-keep-alive | | Whether keep alive is enabled on the channel.
|spring.grpc.client.default-channel.health.enabled | | Whether to enable client-side health check for the channel.
|spring.grpc.client.default-channel.address | `+++static://localhost:9090+++` | The target address uri to connect to.
|spring.grpc.client.default-channel.default-load-balancing-policy | `+++round_robin+++` | The default load balancing policy the channel should use.
|spring.grpc.client.default-channel.enable-keep-alive | `+++false+++` | Whether keep alive is enabled on the channel.
|spring.grpc.client.default-channel.health.enabled | `+++false+++` | Whether to enable client-side health check for the channel.
|spring.grpc.client.default-channel.health.service-name | | Name of the service to check health on.
|spring.grpc.client.default-channel.idle-timeout | | The duration without ongoing RPCs before going to idle mode.
|spring.grpc.client.default-channel.keep-alive-time | | The delay before sending a keepAlive. Note that shorter intervals increase the network burden for the server and this value can not be lower than 'permitKeepAliveTime' on the server.
|spring.grpc.client.default-channel.keep-alive-timeout | | The default timeout for a keepAlives ping request.
|spring.grpc.client.default-channel.keep-alive-without-calls | | Whether a keepAlive will be performed when there are no outstanding RPC on a connection.
|spring.grpc.client.default-channel.max-inbound-message-size | | Maximum message size allowed to be received by the channel (default 4MiB). Set to '-1' to use the highest possible limit (not recommended).
|spring.grpc.client.default-channel.max-inbound-metadata-size | | Maximum metadata size allowed to be received by the channel (default 8KiB). Set to '-1' to use the highest possible limit (not recommended).
|spring.grpc.client.default-channel.negotiation-type | | The negotiation type for the channel.
|spring.grpc.client.default-channel.secure | | Flag to say that strict SSL checks are not enabled (so the remote certificate could be anonymous).
|spring.grpc.client.default-channel.idle-timeout | `+++20s+++` | The duration without ongoing RPCs before going to idle mode.
|spring.grpc.client.default-channel.keep-alive-time | `+++5m+++` | The delay before sending a keepAlive. Note that shorter intervals increase the network burden for the server and this value can not be lower than 'permitKeepAliveTime' on the server.
|spring.grpc.client.default-channel.keep-alive-timeout | `+++20s+++` | The default timeout for a keepAlives ping request.
|spring.grpc.client.default-channel.keep-alive-without-calls | `+++false+++` | Whether a keepAlive will be performed when there are no outstanding RPC on a connection.
|spring.grpc.client.default-channel.max-inbound-message-size | `+++4194304B+++` | Maximum message size allowed to be received by the channel (default 4MiB). Set to '-1' to use the highest possible limit (not recommended).
|spring.grpc.client.default-channel.max-inbound-metadata-size | `+++8192B+++` | Maximum metadata size allowed to be received by the channel (default 8KiB). Set to '-1' to use the highest possible limit (not recommended).
|spring.grpc.client.default-channel.negotiation-type | `+++plaintext+++` | The negotiation type for the channel.
|spring.grpc.client.default-channel.secure | `+++true+++` | Flag to say that strict SSL checks are not enabled (so the remote certificate could be anonymous).
|spring.grpc.client.default-channel.ssl.bundle | | SSL bundle name.
|spring.grpc.client.default-channel.ssl.enabled | | Whether to enable SSL support. Enabled automatically if "bundle" is provided unless specified otherwise.
|spring.grpc.client.default-channel.user-agent | | The custom User-Agent for the channel.
|spring.grpc.server.address | | The address to bind to. could be a host:port combination or a pseudo URL like static://host:port. Can not be set if host or port are set independently.
|spring.grpc.server.health.actuator.enabled | | Whether to adapt Actuator health indicators into gRPC health checks.
|spring.grpc.server.exception-handling.enabled | `+++true+++` | Whether to enable user-defined global exception handling on the gRPC server.
|spring.grpc.server.health.actuator.enabled | `+++true+++` | Whether to adapt Actuator health indicators into gRPC health checks.
|spring.grpc.server.health.actuator.health-indicator-paths | | List of Actuator health indicator paths to adapt into gRPC health checks.
|spring.grpc.server.health.actuator.update-initial-delay | | The initial delay before updating the health status the very first time.
|spring.grpc.server.health.actuator.update-overall-health | | Whether to update the overall gRPC server health (the '' service) with the aggregate status of the configured health indicators.
|spring.grpc.server.health.actuator.update-rate | | How often to update the health status.
|spring.grpc.server.health.enabled | | Whether to auto-configure Health feature on the gRPC server.
|spring.grpc.server.host | | Server address to bind to. The default is any IP address ('*').
|spring.grpc.server.health.actuator.update-initial-delay | `+++5s+++` | The initial delay before updating the health status the very first time.
|spring.grpc.server.health.actuator.update-overall-health | `+++true+++` | Whether to update the overall gRPC server health (the '' service) with the aggregate status of the configured health indicators.
|spring.grpc.server.health.actuator.update-rate | `+++5s+++` | How often to update the health status.
|spring.grpc.server.health.enabled | `+++true+++` | Whether to auto-configure Health feature on the gRPC server.
|spring.grpc.server.host | `+++*+++` | Server address to bind to. The default is any IP address ('*').
|spring.grpc.server.keep-alive.max-age | | Maximum time a connection may exist before being gracefully terminated (default infinite).
|spring.grpc.server.keep-alive.max-age-grace | | Maximum time for graceful connection termination (default infinite).
|spring.grpc.server.keep-alive.max-idle | | Maximum time a connection can remain idle before being gracefully terminated (default infinite).
|spring.grpc.server.keep-alive.permit-time | | Maximum keep-alive time clients are permitted to configure (default 5m).
|spring.grpc.server.keep-alive.permit-without-calls | | Whether clients are permitted to send keep alive pings when there are no outstanding RPCs on the connection (default false).
|spring.grpc.server.keep-alive.time | | Duration without read activity before sending a keep alive ping (default 2h).
|spring.grpc.server.keep-alive.timeout | | Maximum time to wait for read activity after sending a keep alive ping. If sender does not receive an acknowledgment within this time, it will close the connection (default 20s).
|spring.grpc.server.max-inbound-message-size | | Maximum message size allowed to be received by the server (default 4MiB).
|spring.grpc.server.max-inbound-metadata-size | | Maximum metadata size allowed to be received by the server (default 8KiB).
|spring.grpc.server.port | | Server port to listen on. When the value is 0, a random available port is selected. The default is 9090.
|spring.grpc.server.shutdown-grace-period | | Maximum time to wait for the server to gracefully shutdown. When the value is negative, the server waits forever. When the value is 0, the server will force shutdown immediately. The default is 30 seconds.
|spring.grpc.server.keep-alive.permit-time | `+++5m+++` | Maximum keep-alive time clients are permitted to configure (default 5m).
|spring.grpc.server.keep-alive.permit-without-calls | `+++false+++` | Whether clients are permitted to send keep alive pings when there are no outstanding RPCs on the connection (default false).
|spring.grpc.server.keep-alive.time | `+++2h+++` | Duration without read activity before sending a keep alive ping (default 2h).
|spring.grpc.server.keep-alive.timeout | `+++20s+++` | Maximum time to wait for read activity after sending a keep alive ping. If sender does not receive an acknowledgment within this time, it will close the connection (default 20s).
|spring.grpc.server.max-inbound-message-size | `+++4194304B+++` | Maximum message size allowed to be received by the server (default 4MiB).
|spring.grpc.server.max-inbound-metadata-size | `+++8192B+++` | Maximum metadata size allowed to be received by the server (default 8KiB).
|spring.grpc.server.observations.enabled | `+++true+++` | Whether to enable Observations on the server.
|spring.grpc.server.port | `+++9090+++` | Server port to listen on. When the value is 0, a random available port is selected. The default is 9090.
|spring.grpc.server.reflection.enabled | `+++true+++` | Whether to enable Reflection on the gRPC server.
|spring.grpc.server.shutdown-grace-period | `+++30s+++` | Maximum time to wait for the server to gracefully shutdown. When the value is negative, the server waits forever. When the value is 0, the server will force shutdown immediately. The default is 30 seconds.
|spring.grpc.server.ssl.bundle | | SSL bundle name.
|spring.grpc.server.ssl.client-auth | | Client authentication mode.
|spring.grpc.server.ssl.client-auth | `+++none+++` | Client authentication mode.
|spring.grpc.server.ssl.enabled | | Whether to enable SSL support. Enabled automatically if "bundle" is provided unless specified otherwise.
|spring.grpc.server.ssl.secure | | Flag to indicate that client authentication is secure (i.e. certificates are checked). Do not set this to false in production.
|spring.grpc.server.ssl.secure | `+++true+++` | Flag to indicate that client authentication is secure (i.e. certificates are checked). Do not set this to false in production.

|===
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ static class GrpcServerFactoryConfiguration {

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(GrpcServlet.class)
static class GrpcServletConfiguration {

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,28 @@

package org.springframework.grpc.autoconfigure.server;

import io.grpc.BindableService;
import io.grpc.ServerServiceDefinition;
import io.grpc.internal.GrpcUtil;
import io.grpc.servlet.jakarta.ServletServerBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;

import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.grpc.autoconfigure.server.GrpcServerFactoryAutoConfiguration.GrpcServletConfiguration;
import org.springframework.grpc.server.ServerBuilderCustomizer;
import org.springframework.util.unit.DataSize;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import io.grpc.BindableService;
import io.grpc.ServerServiceDefinition;
import io.grpc.internal.GrpcUtil;
import io.grpc.servlet.jakarta.GrpcServlet;
import io.grpc.servlet.jakarta.ServletServerBuilder;

/**
* Tests for {@link GrpcServerAutoConfiguration}.
Expand All @@ -59,14 +62,22 @@ private WebApplicationContextRunner contextRunner() {
void whenGrpcNotOnClasspathAutoConfigurationIsSkipped() {
this.contextRunner()
.withClassLoader(new FilteredClassLoader(BindableService.class))
.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerAutoConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(GrpcServletConfiguration.class)
.doesNotHaveBean(ServletRegistrationBean.class));
}

@Test
void whenNoBindableServicesRegisteredAutoConfigurationIsSkipped() {
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(GrpcServerAutoConfiguration.class))
.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerAutoConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(GrpcServletConfiguration.class)
.doesNotHaveBean(ServletRegistrationBean.class));
}

@Test
void whenGrpcServletNotOnClasspathAutoConfigurationIsSkipped() {
this.contextRunner()
.withClassLoader(new FilteredClassLoader(GrpcServlet.class))
.run((context) -> assertThat(context).doesNotHaveBean(GrpcServletConfiguration.class)
.doesNotHaveBean(ServletRegistrationBean.class));
}

Expand Down

0 comments on commit c52d6d8

Please sign in to comment.