Hello Stream - Server Streaming RPC
This example builds on 01_hello_world by adding server streaming, where a single request receives multiple responses over time.
What You'll Learn
- Adding a streaming RPC method to a proto service
- Implementing a server streaming handler
- Using
ServerStreamto send multiple responses - Handling client cancellation
Proto Definition
// greeter.proto
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
rpc SayHelloStream (HelloRequest) returns (stream HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}The stream keyword before HelloReply indicates this method returns multiple responses.
Server Implementation
using gRPCServer# Include generated typesinclude("generated/helloworld/helloworld.jl")using .helloworld# Handlersfunction say_hello(ctx::ServerContext, request::HelloRequest)::HelloReply @info "Received request" name=request.name request_id=ctx.request_id HelloReply("Hello, $(request.name)!")endfunction say_hello_stream( ctx::ServerContext, request::HelloRequest, stream::ServerStream{HelloReply})::Nothing for i in 1:5 if is_cancelled(ctx) @warn "Stream cancelled by client" return nothing end send!(stream, HelloReply("Hello $(i), $(request.name)!")) sleep(0.5) end return nothingend# Register the service with the codegen registration functionfunction main() host = "127.0.0.1" port = 50051 server = GRPCServer(host, port; enable_health_check = true, enable_reflection = true ) register_Greeter!(server; SayHello = say_hello, SayHelloStream = say_hello_stream) @info "gRPC server starting" host=host port=port run(server)endmain()Key Concepts
Streaming Handler Signature
Server streaming handlers receive an additional parameter:
function handler( ctx::ServerContext, request::RequestType, stream::ServerStream{ResponseType})::NothingThe handler returns Nothing instead of a response type.
Sending Responses
Use send!(stream, response) to send each response:
for item in items send!(stream, ResponseType(...))endCancellation Handling
Check is_cancelled(ctx) to detect client cancellation:
if is_cancelled(ctx) @warn "Client cancelled the stream" return nothingendThis is important for long-running streams to avoid wasting resources.
Registration
The generated register_Greeter! registers both RPCs in one call:
register_Greeter!(server; SayHello = say_hello, SayHelloStream = say_hello_stream)Each keyword accepts a handler or a (handler, raw_request, raw_response) tuple; handler signatures are validated at registration time.
Testing
Run the Server
cd examples/02_hello_stream
julia --project=../.. server.jlCall Unary RPC
grpcurl -plaintext -d '{"name": "Julia"}' localhost:50051 helloworld.Greeter/SayHelloExpected output:
{
"message": "Hello, Julia!"
}Call Streaming RPC
grpcurl -plaintext -d '{"name": "Julia"}' localhost:50051 helloworld.Greeter/SayHelloStreamExpected output (5 messages over ~2.5 seconds):
{
"message": "Hello 1, Julia!"
}
{
"message": "Hello 2, Julia!"
}
{
"message": "Hello 3, Julia!"
}
{
"message": "Hello 4, Julia!"
}
{
"message": "Hello 5, Julia!"
}Other Streaming Patterns
Client Streaming
Single response after receiving multiple requests:
function handler(ctx::ServerContext, stream::ClientStream{RequestType}) for request in stream # Process each request end return ResponseType(...)endBidirectional Streaming
Multiple requests and responses simultaneously:
function handler(ctx::ServerContext, stream::BidiStream{RequestType, ResponseType}) for request in stream send!(stream, ResponseType(...)) end close!(stream) return nothingendBoth patterns are registered the same way through the generated functions — see 03_sum_numbers and 04_chat.
Next Steps
Proceed to Sum Numbers to learn about client streaming, where multiple requests produce a single response.