Add experimental gRPC streaming over the event bus#281
Conversation
ad3f1ff to
782c880
Compare
782c880 to
06fce04
Compare
| EventBusHeaders.encodeMultiMap(HEADER_PREFIX, requestHeaders, options.getHeaders()); | ||
| } | ||
|
|
||
| long clientStreamId = endpoint.register(this); |
There was a problem hiding this comment.
we should split registration and stream ID generation in two steps, so we register only when the interaction on the following EventBus request is successful
we should have a monotonic stream ID sequence that is allocated when the stream is created and sent when the result of the event-bus interaction is received
| HalfClose half_close = 7; // client to server, end of the request stream | ||
| Trailers trailers = 8; // server to client, terminates the call | ||
| Cancel cancel = 9; // either direction, abnormal termination | ||
| Headers headers = 10; // server to client, response metadata, before the first message |
There was a problem hiding this comment.
I think we don't need this frame because we can make this part of the initial request/response interaction along with the initialized response in clear format (like for unary)
| uint64 stream_sequence = 2; // per-stream, monotonic, advances on Message frames only | ||
|
|
||
| oneof frame { | ||
| Initialize initialize = 3; // client to server, the opening request body |
There was a problem hiding this comment.
I don't think we need initialize/initialized frames here, we should keep protobuf frames only for the private address communication
| return id; | ||
| } | ||
|
|
||
| void closed(FrameHandler stream) { |
There was a problem hiding this comment.
are we testing that an an initial or streaming failure correctly remove the stream from the map ?
| import io.vertx.core.eventbus.Message; | ||
| import io.vertx.grpc.eventbus.transport.v1alpha.TransportFrame; | ||
|
|
||
| interface FrameHandler extends Closeable { |
There was a problem hiding this comment.
for the moment we don't need that interface, we should just make in an abstract method of EventBusStreamEndpoint
| abstract class EventBusStreamEndpoint { | ||
|
|
||
| protected final ConcurrentMap<Long, FrameHandler> streams = new ConcurrentHashMap<>(); | ||
| protected volatile int maxConcurrentStreams = EventBusGrpcServerOptions.DEFAULT_MAX_CONCURRENT_STREAMS; |
There was a problem hiding this comment.
it should be removed.
I don't think we can support this because there is no way to identify the remote side we will handle when using the event-bus due to load balancing, the main purpose of max concurrent streams is to protect the producer and when using load balancing we just use an event-bus address.
| public interface ServiceMethod<I, O> { | ||
|
|
||
| static <Req, Resp> ServiceMethod<Resp, Req> client(ServiceName serviceName, String methodName, GrpcMessageEncoder<Req> encoder, GrpcMessageDecoder<Resp> decoder) { | ||
| return client(serviceName, methodName, MethodType.UNARY, encoder, decoder); |
There was a problem hiding this comment.
we should set null instead of MethodType.UNARY instead because this is not available and unknown. I'd prefer a bug with an NPE rather than a misbehavior.
| return client(serviceName, methodName, MethodType.UNARY, encoder, decoder); | ||
| } | ||
|
|
||
| static <Req, Resp> ServiceMethod<Resp, Req> client(ServiceName serviceName, String methodName, MethodType type, GrpcMessageEncoder<Req> encoder, GrpcMessageDecoder<Resp> decoder) { |
There was a problem hiding this comment.
instead of this we should instead have booleain indicating cardinality for both sides of the service and avoid expose MethodType at the moment, it should remain internal.
Signed-off-by: Daniel Fiala <danfiala23@gmail.com>
…server streaming call initialization. Motivation: - Transition to `v1alpha` schema for EventBus transport messages for better compatibility and clarity. - Simplify and improve the initialization of server-side streaming calls with a more modular design. Changes: - Updated protobuf definitions and transport schema from `eventbus.transport` to `eventbus.transport.v1alpha`. - Refactored `EventBusGrpcServerStreamingCall` to use a dedicated `init` method for inbound message consumer setup. - Simplified server-side streaming call logic by removing `AtomicReference` and directly managing completion callbacks. - Updated documentation to specify the new schema path and updated associated examples.
…ams, update transport schema to `Initialize`/`Initialized` handshake. Motivation: - Transition from per-call addresses to multiplexed streams over shared private addresses, reducing registration churn and improving scalability. - Replace `Ack` with `Initialize`/`Initialized` handshake for clearer and more efficient stream initialization. - Enhance stream management with session-level abstractions. Changes: - Introduced `FrameHandler` interface to handle multiplexed streams. - Updated transport schema to use `Initialize`/`Initialized` messages. - Refactored `EventBusGrpcClientStreamingCall` and `EventBusGrpcServerStreamingCall` for improved stream lifecycle management. - Updated documentation and protocol definitions (`eventbus.transport.proto`) to reflect the new design. - Improved error handling and stream termination logic.
…ed async handling. Motivation: - Enhance the usability and consistency of the EventBus gRPC API by having client and server initialization methods return `Future` instead of direct instances. - Ensure proper integration with Vert.x's asynchronous model. Changes: - Updated `EventBusGrpcClient.client` and `EventBusGrpcServer.server` methods to return `Future` instances. - Refactored related tests and examples to use the updated async API. - Improved error handling and initialization completion by leveraging `Future` chaining. - Adjusted internal implementations to remove lazy registration in favor of explicit `bind()` calls.
…rame schema. Motivation: - Replace protobuf `Initialize`/`Initialized` handshake with explicit headers for reduced complexity and improved protocol clarity. - Simplify frame schema by removing unused message types and focusing on active bidirectional streaming fields. Changes: - Removed `Initialize`/`Initialized` protobuf messages from transport schema. - Refactored `EventBusGrpcServer` and `EventBusGrpcClient` to utilize headers for streaming handshake and session demultiplexing. - Introduced `StreamRegistration` abstraction for improved stream lifecycle management. - Updated tests to include new error handling scenarios for handshake validation. - Adjusted documentation to reflect the simplified method-level streaming protocol.
…pport max concurrent streams cap. Motivation: - Introduce configurable server options to improve flexibility and manageability of the gRPC server. - Add a cap on maximum concurrent streams to handle resource exhaustion effectively. Changes: - Added `EventBusGrpcServerOptions` to manage server configurations like `maxConcurrentStreams`. - Updated gRPC server methods to accept `EventBusGrpcServerOptions` for initialization. - Enhanced error handling to reject excessive stream openings with `RESOURCE_EXHAUSTED`. - Added tests for configurable options and error handling scenarios. - Refactored related implementation to handle the new options efficiently.
… server. Motivation: - Allow gRPC client and server to support multiple wire formats (e.g., PROTOBUF, JSON) for improved flexibility and interoperability. - Enable validation and rejection of unsupported wire formats at runtime. Changes: - Added `EventBusGrpcServerOptions` and `EventBusGrpcClientOptions` to configure supported wire formats. - Updated server to validate incoming wire formats against configured options and reject unsupported formats with `UNIMPLEMENTED` status. - Enhanced frame encoding/decoding logic to handle dynamic wire formats. - Introduced new helper methods for setting and validating wire formats in client and server implementations. - Added unit tests to verify correct handling of wire format configurations and error scenarios.
…tocol details. Motivation: - Improve documentation clarity by simplifying explanations and updating terminology to reflect current design. - Align descriptions with recent refactors and schema changes for better readability and understanding. Changes: - Simplified explanation of gRPC stream handling via the event bus, including handshake and streaming mechanisms. - Updated sections to match the latest transport schema and protocol design. - Reorganized content for better flow and removed redundant details. - Added examples and references for improved context.
… concurrent streams cap. Motivation: - Simplify the gRPC stream initialization protocol by removing unnecessary complexities in frame schema and handshake. - Eliminate the max concurrent streams cap for better scalability and to streamline server options. Changes: - Removed `maxConcurrentStreams` functionality and related validations from `EventBusGrpcServerOptions`. - Simplified stream initialization logic by replacing `MethodType` with explicit client/server streaming flags. - Refactored `ServiceMethod` to use boolean flags (`clientStreaming`, `serverStreaming`) instead of method type enums. - Updated test cases and documentation to reflect schema and initialization changes. - Consolidated stream management interfaces by removing `FrameHandler` and merging its functionality into `EventBusGrpcStreamBase`. - Updated generated code and templates to align with the simplified schema.
cbf9ee9 to
5697d2f
Compare
| /** | ||
| * The cardinality of a gRPC service method. | ||
| */ | ||
| public enum MethodType { |
There was a problem hiding this comment.
I think for now I would like to avoid introducing this type as it is only used in this module and instead stick with the two booleans used, probably those booleans should be Boolean to indicate when the information is unknown
| private final EventBus eventBus; | ||
| private final ServiceName serviceName; | ||
| private final String methodName; | ||
| private final Deque<GrpcMessage> pending = new ArrayDeque<>(); |
There was a problem hiding this comment.
init that in the constructor along with other inits
| private Duration timeout; | ||
|
|
||
| private boolean ended; | ||
| private State state = State.IDLE; |
There was a problem hiding this comment.
init that in the constructor along with other inits
| } | ||
| } | ||
|
|
||
| protected void writeMessage(GrpcMessage message) { |
There was a problem hiding this comment.
We need to add message write future return with the following modification:
the EventBusGrpcStreamBase#writeMessage(GrpcMessage) should return a Future<Void>, to implement this:
- the
EventBusGrpcStreamBase#outboundQueueshould be modified to contain an object that has a Promise in addition of the message itself, e.g. aMessageWriteinternal class - the method
EventBusGrpcStreamBase#sendTransportFrameshould be modified to return aFuture<Void>
The implementation of sendTransportFrame should use a MessageProducer instead of the event bus directly, MessageProducer#write will return a Future<Void>, this producer for sending can be obtained with EventBus#sender(String address), before writing the message delivery options should be set on the producer (and then set to null). I think this is OK but not convenient, so I think we should overload MessageProducer#write(T) with MessageProducer#write(T, DeliveryOptions) in vertx-core at some point.
…ient/server streaming flags. Motivation: - Simplify gRPC method definitions by replacing the `MethodType` enum with boolean flags for `clientStreaming` and `serverStreaming`. - Align with recent changes in transport schema and improve readability. Changes: - Removed `MethodType` and replaced its usage with `Boolean clientStreaming` and `Boolean serverStreaming` in `ServiceMethod` and related interfaces. - Updated `TranscodingServiceMethod` and `TranscodingInvoker` implementations to reflect the new flags. - Modified template files, generated code, and test cases to align with updated method definitions. - Added a new example for server streaming with transcoding options.
8e25a27 to
62edcd5
Compare
…ect instantiation consistency. Motivation: - Ensure proper initialization of `pending` and `state` fields during object construction to avoid potential null pointer exceptions and improve code clarity. Changes: - Move `pending` and `state` field initializations from declarations to the constructor. - Removed default initializations from field declarations.
Motivation:
Add experimental gRPC streaming over the event bus