Runnable Java examples from the core repository, built with Gradle, and how to start a server for them.
Runnable examples live in the examples/java directory of the core repository as a standalone Gradle project. The project builds against the in-repo SDK (via an includeBuild substitution), so the examples always match the SDK source in the same checkout. Java 17 or newer is required. The included gradlew wrapper downloads the pinned Gradle version on first run.
Starting the server
These examples target server 0.9.0 and speak the VSR (Viewstamped Replication) wire protocol. Build the SDK and server from the same checkout for unreleased changes. The examples log in as iggy/iggy. From the repository root, start a disposable development server with no IGGY_ROOT_USERNAME or IGGY_ROOT_PASSWORD overrides:
cargo run --bin iggy-server -- --fresh --with-default-root-credentials--fresh wipes this replica's local data directory (local_data by default). Environment credentials take precedence over the flag, and bootstrap settings do not replace recovered credentials. A fresh cluster replica can recover credentials from peers. This setup is intended only for development and testing.
Running the examples
Run each example from the examples/java directory with its Gradle task. Run the producer before its consumer. The ordinary consumers keep their cursor in memory and start from offset 0 or the earliest retained message on each run; the multi-tenant consumer uses consumer groups and server-managed offsets.
-
gettingstarted - basic blocking producer and consumer, the best starting point.
./gradlew runGettingStartedProducer ./gradlew runGettingStartedConsumer -
messageheaders - message metadata via custom header keys and values, with a
message_typeheader selecting the application handler../gradlew runMessageHeadersProducer ./gradlew runMessageHeadersConsumer -
messageenvelope - JSON envelope pattern for polymorphic message handling (order events wrapped in envelopes for type identification).
./gradlew runMessageEnvelopeProducer ./gradlew runMessageEnvelopeConsumer -
multitenant - multi-tenant isolation: per-tenant streams, users with stream-specific permissions, and concurrent producers and consumers across tenants.
./gradlew runMultiTenantProducer ./gradlew runMultiTenantConsumer -
sinkdataproducer - high-volume data generation (100 batches of 1000 to 1099 messages) with realistic records, for testing and benchmarking.
./gradlew runSinkDataProducer -
streambuilder - a combined producer and consumer in a single class. It deletes its
test_streamstream after the run../gradlew runStreamBasic -
async - the async client:
CompletableFuturechaining, submitting multiple sends without blocking, backpressure, error recovery with exponential backoff, and thread pool separation../gradlew runAsyncProducer ./gradlew runAsyncConsumer -
tcptls - TLS-encrypted TCP connections with CA certificate verification. Requires a TLS-enabled server. Run this server command from the repository root:
IGGY_TCP_TLS_ENABLED=true \ IGGY_TCP_TLS_CERT_FILE=core/certs/iggy_cert.pem \ IGGY_TCP_TLS_KEY_FILE=core/certs/iggy_key.pem \ cargo run --bin iggy-server -- --fresh --with-default-root-credentialsThe same data and credential prerequisites apply. These certificates are for development only. Return to
examples/javafor the client commands; their CA path is relative to that directory../gradlew runTcpTlsProducer ./gradlew runTcpTlsConsumer
Blocking vs. async
Use the blocking client for scripts, CLI tools, integration tests, and anywhere sequential code is easier to reason about. Use the async client for high throughput, reactive applications, and composing non-blocking requests with CompletableFuture. The async client runs I/O on Netty event loop threads: never block them with .join(), .get(), Thread.sleep(), or blocking I/O inside thenApply/thenAccept. Offload blocking work with thenApplyAsync(fn, executor). The examples/java README covers these async patterns in detail.
