Skip to content

Integration client - #646

Merged
slinkydeveloper merged 24 commits into
mainfrom
integration-client
Oct 15, 2026
Merged

slinkydeveloper merged 24 commits into
mainfrom
integration-client

Conversation

@slinkydeveloper

@slinkydeveloper slinkydeveloper commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

Restate Integration Client

You can use the Integration API to turn any source of events into Restate invocations.

Use an integration client to send invocations to Restate using the Integration API.

Installation

Add dev.restate:integration-client to your dependencies.

Create a client

Create one client for your Restate ingress URL and close it when your integration shuts down:

try (IntegrationClient client = IntegrationClient.builder("http://localhost:8080").build()) {
  // Use client
}

Simple producer

Use Producer when your source does not provide stable offsets that you can replay.
The client assigns an offset to each invocation.
Call flush() before closing the producer to wait until Restate has durably committed everything you sent:

try (Producer producer = client.newProducer()) {
  for (SourceRecord record : records) {
    producer.send(
        Invocation.create()
            .setServiceName("OrderService")
            .setHandlerName("ingest")
            .putHeader("content-type", "application/json")
            .setBody(record.payload()));
  }
  producer.flush();
}

Exactly once producer

Use ExactlyOnceProducer when your source provides stable, strictly increasing offsets,
and choose a producer ID that remains stable across restarts and is unique to that offset sequence.
After flush() returns, you can checkpoint the returned offset in your source:

try (ExactlyOnceProducer producer = client.newExactlyOnceProducer("orders/partition-0")) {
  for (SourceRecord record : sourceRecords) {
    producer.send(
        record.offset(),
        Invocation.create()
            .setServiceName("OrderService")
            .setHandlerName("ingest")
            .putHeader("content-type", "application/json")
            .setBody(record.payload()));
  }
  long committedOffset = producer.flush();
  // Checkpoint committedOffset in your source
}

Producer default fields

Producers accept InvocationMetadata when every invocation shares fields such as the target service, handler, or headers.
Set defaults to avoid sending over and over the same fields in every invocation.

Fields set on an individual invocation override these defaults.

InvocationMetadata defaults =
    InvocationMetadata.create()
        .setServiceName("OrderService")
        .setHandlerName("ingest")
        .putHeader("content-type", "application/json");

try (Producer producer = client.newProducer(defaults)) {
  for (SourceRecord record : records) {
    producer.send(Invocation.create().setBody(record.payload()));
  }
  producer.flush();
}

More

For configuration options and advanced usage, see the Integration client Javadocs.

@github-actions

github-actions Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

  8 files  ±0    8 suites  ±0   3m 49s ⏱️ +9s
 60 tests +1   60 ✅ +1  0 💤 ±0  0 ❌ ±0 
267 runs  +1  267 ✅ +1  0 💤 ±0  0 ❌ ±0 

Results for commit ba77fb5. ± Comparison against base commit b718ad1.

♻️ This comment has been updated with latest results.

@slinkydeveloper
slinkydeveloper merged commit 202c7d7 into main Oct 15, 2026
8 checks passed
@slinkydeveloper
slinkydeveloper deleted the integration-client branch October 15, 2026 09:50
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant