Skip to content
Open
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
2 changes: 1 addition & 1 deletion vertx-grpc-docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
<artifactId>vertx-grpc-protoc-plugin2</artifactId>
<version>${project.version}</version>
<mainClass>io.vertx.grpc.plugin.VertxGrpcGenerator</mainClass>
<options>grpc-client=true,grpc-service=true,grpc-io=true</options>
<options>grpc-client=true,grpc-service=true,grpc-io=true,event-bus-handler=true,event-bus-proxy=true</options>
</jvmMavenPlugin>
</jvmMavenPlugins>
<!--jvmMavenPlugins>
Expand Down
48 changes: 48 additions & 0 deletions vertx-grpc-docs/src/main/asciidoc/plugin.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ By default, the plugin generates both client and service files. If you need only
- _[--]grpc-transcoding[=true/false]_: whether to generate transcoding options for methods with HTTP annotations
- _[--]vertx-codegen[=true/false]_: whether to add Vert.x annotations to the generated classes (`@VertxGen`) By default, this is disabled
- _[--]service-prefix[=Your Name]_: generate service classes with a prefix. For example, if you set it to `MyService`, the generated service class will be `MyServiceGreeterService` instead of `GreeterService`.
- _[--]event-bus-handler[=true/false]_: generate event bus handler files that register event bus consumers for unary methods, delegating to the service contract
- _[--]event-bus-proxy[=true/false]_: generate event bus proxy files that implement the service contract by sending messages over the event bus

* [--] This means the argument can be prefixed with `--` when used as JVM arguments, but should be used without `--` when specified in the options tag. If possible, users should use plugin options as a more universal protoc plugin approach.
* [=value] This means the argument can optionally specify a value. For boolean arguments (true/false), if no value is specified, the default is `true` when the argument is present. For string arguments like `service-prefix`, a value must be provided.
Expand Down Expand Up @@ -252,3 +254,49 @@ Additionally, when `grpc-io=true` is enabled, the plugin generates:
|Compatibility layer for using the service with standard `io.grpc` stubs and existing gRPC/IO ecosystem
|<<idiomatic-server-io,gRPC/IO Server>> / <<idiomatic-client-io,gRPC/IO Client>>
|===

When `event-bus-handler=true` and/or `event-bus-proxy=true` are enabled, the plugin also generates:

[cols="2,4", options="header"]
|===
|Generated File |Description

|`GreeterEventBusHandler.java`
|Registers event bus consumers for unary methods, delegating to the service contract

|`GreeterEventBusProxy.java`
|Implements the service contract by sending messages over the event bus
|===

=== Event Bus Integration

Instead of calling a gRPC service over the network, you can expose it on the Vert.x event bus. This is useful when your services run inside the same cluster and you want to avoid the overhead of HTTP/2 connections. Consumers and producers communicate through the event bus instead.

Each unary method is mapped to an event bus address of the form `{protoPackage}.{ServiceName}/{MethodName}`, e.g. `examples.grpc.Greeter/SayHello`. Request and response messages are serialized as protobuf bytes in a `Buffer`.

NOTE: Only unary-unary methods are supported. Streaming methods will throw `UnsupportedOperationException`.

==== Registering a handler

To expose a service on the event bus, create a handler with your service implementation and register it:

[source,java]
----
{@link examples.GrpcEventBusExamples#registerHandler}
----

==== Calling a service through the event bus

The generated proxy implements the same service contract interface, so you can use it just like a regular client:

[source,java]
----
{@link examples.GrpcEventBusExamples#useProxy}
----

You can also pass `DeliveryOptions` to configure timeouts or headers:

[source,java]
----
{@link examples.GrpcEventBusExamples#useProxyWithOptions}
----
45 changes: 45 additions & 0 deletions vertx-grpc-docs/src/main/java/examples/GrpcEventBusExamples.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package examples;

import examples.grpc.*;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.DeliveryOptions;
import io.vertx.docgen.Source;

@Source
public class GrpcEventBusExamples {

public void registerHandler(Vertx vertx) {
Greeter service = new Greeter() {
@Override
public Future<HelloReply> sayHello(HelloRequest request) {
return Future.succeededFuture(
HelloReply.newBuilder()
.setMessage("Hello " + request.getName())
.build());
}
};
GreeterEventBusHandler handler = new GreeterEventBusHandler(service);
handler.register(vertx.eventBus());
}

public void useProxy(Vertx vertx) {
GreeterEventBusProxy proxy = new GreeterEventBusProxy(vertx);
proxy.sayHello(HelloRequest.newBuilder().setName("World").build())
.onSuccess(reply -> {
System.out.println("Received: " + reply.getMessage());
})
.onFailure(err -> {
System.err.println("Failed: " + err.getMessage());
});
}

public void useProxyWithOptions(Vertx vertx) {
DeliveryOptions options = new DeliveryOptions().setSendTimeout(5000);
GreeterEventBusProxy proxy = new GreeterEventBusProxy(vertx, options);
proxy.sayHello(HelloRequest.newBuilder().setName("World").build())
.onSuccess(reply -> {
System.out.println("Received: " + reply.getMessage());
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package examples.grpc;

import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.EventBus;

/**
* <p>Event bus handler for the Greeter gRPC service.</p>
*
* <p>Registers event bus consumers for each unary-unary method, delegating to the
* {@link Greeter} contract interface.</p>
*
* <p>Address format: {@code examples.grpc.Greeter/MethodName}</p>
*/
public class GreeterEventBusHandler {

private final Greeter service;

public GreeterEventBusHandler(Greeter service) {
this.service = service;
}

/**
* Registers event bus consumers for all unary-unary methods of this service.
*
* @param eventBus the Vert.x event bus to register consumers on
*/
public void register(EventBus eventBus) {
eventBus.consumer("examples.grpc.Greeter/SayHello", this::handleSayHello);
}

private void handleSayHello(Message<Buffer> message) {
try {
examples.grpc.HelloRequest request = examples.grpc.HelloRequest.parseFrom(message.body().getBytes());
service.sayHello(request).onComplete(ar -> {
if (ar.succeeded()) {
message.reply(Buffer.buffer(ar.result().toByteArray()));
} else {
message.fail(500, ar.cause().getMessage());
}
});
} catch (Exception e) {
message.fail(500, e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package examples.grpc;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.DeliveryOptions;
import io.vertx.core.streams.ReadStream;

/**
* <p>Event bus proxy for the Greeter gRPC service.</p>
*
* <p>Implements the {@link Greeter} contract interface by sending protobuf-serialized
* messages over the Vert.x event bus. Only unary-unary methods are supported.</p>
*
* <p>Address format: {@code examples.grpc.Greeter/MethodName}</p>
*/
public class GreeterEventBusProxy implements Greeter {

private final Vertx vertx;
private final DeliveryOptions options;

public GreeterEventBusProxy(Vertx vertx) {
this(vertx, null);
}

public GreeterEventBusProxy(Vertx vertx, DeliveryOptions options) {
this.vertx = vertx;
this.options = options;
}

@Override
public Future<examples.grpc.HelloReply> sayHello(examples.grpc.HelloRequest request) {
DeliveryOptions deliveryOptions = (options != null) ? new DeliveryOptions(options) : new DeliveryOptions();
return vertx.eventBus().<Buffer>request("examples.grpc.Greeter/SayHello", Buffer.buffer(request.toByteArray()), deliveryOptions)
.map(msg -> {
try {
return examples.grpc.HelloReply.parseFrom(msg.body().getBytes());
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package examples.grpc;

import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.EventBus;

/**
* <p>Event bus handler for the Streaming gRPC service.</p>
*
* <p>Registers event bus consumers for each unary-unary method, delegating to the
* {@link Streaming} contract interface.</p>
*
* <p>Address format: {@code examples.grpc.Streaming/MethodName}</p>
*/
public class StreamingEventBusHandler {

private final Streaming service;

public StreamingEventBusHandler(Streaming service) {
this.service = service;
}

/**
* Registers event bus consumers for all unary-unary methods of this service.
*
* @param eventBus the Vert.x event bus to register consumers on
*/
public void register(EventBus eventBus) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package examples.grpc;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.DeliveryOptions;
import io.vertx.core.streams.ReadStream;

/**
* <p>Event bus proxy for the Streaming gRPC service.</p>
*
* <p>Implements the {@link Streaming} contract interface by sending protobuf-serialized
* messages over the Vert.x event bus. Only unary-unary methods are supported.</p>
*
* <p>Address format: {@code examples.grpc.Streaming/MethodName}</p>
*/
public class StreamingEventBusProxy implements Streaming {

private final Vertx vertx;
private final DeliveryOptions options;

public StreamingEventBusProxy(Vertx vertx) {
this(vertx, null);
}

public StreamingEventBusProxy(Vertx vertx, DeliveryOptions options) {
this.vertx = vertx;
this.options = options;
}

@Override
public Future<ReadStream<examples.grpc.Item>> source(examples.grpc.Empty request) {
throw new UnsupportedOperationException("Streaming methods are not supported over the event bus");
}

@Override
public Future<examples.grpc.Empty> sink(ReadStream<examples.grpc.Item> request) {
throw new UnsupportedOperationException("Streaming methods are not supported over the event bus");
}

@Override
public Future<ReadStream<examples.grpc.Item>> pipe(ReadStream<examples.grpc.Item> request) {
throw new UnsupportedOperationException("Streaming methods are not supported over the event bus");
}
}
2 changes: 1 addition & 1 deletion vertx-grpc-it/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
<artifactId>vertx-grpc-protoc-plugin2</artifactId>
<version>${project.version}</version>
<mainClass>io.vertx.grpc.plugin.VertxGrpcGenerator</mainClass>
<options>grpc-client=true,grpc-service=true,grpc-io=true</options>
<options>grpc-client=true,grpc-service=true,grpc-io=true,event-bus-handler=true,event-bus-proxy=true</options>
</jvmMavenPlugin>
</jvmMavenPlugins>
</configuration>
Expand Down
Loading