If Apache Iggy is useful to you, give it a star on GitHubStar apache/iggy
Apache Iggy
SDKJava

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_type header 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_stream stream after the run.

    ./gradlew runStreamBasic
  • async - the async client: CompletableFuture chaining, 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-credentials

    The same data and credential prerequisites apply. These certificates are for development only. Return to examples/java for 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.

On this page