Skip to content
kzmlabs / flink-statefun

Stateful actors
on Apache Flink

Durable per-key state, exactly-once messaging, Kafka and Kinesis I/O — without writing a Flink job by hand. The actively maintained continuation of Apache Stateful Functions.

Maven Central License OpenSSF Scorecard

What is StateFun Actors?

You write a function keyed by a logical id. The runtime gives it per-key durable state, routes messages to it, replays on failure, and connects it to Kafka and Kinesis. Actor programming on top of Apache Flink — without writing a Flink job by hand.

This is the actively maintained continuation of Apache Stateful Functions: same programming model, current Flink, current Java, restored Kinesis I/O, and a real Kubernetes end-to-end gate before every release.

Without StateFun

public class CounterFunction
    extends KeyedProcessFunction<String, Event, Result> {

  private ValueState<Long> count;

  @Override
  public void open(Configuration cfg) {
    count = getRuntimeContext().getState(
      new ValueStateDescriptor<>("count", Long.class));
  }

  @Override
  public void processElement(Event e, Context ctx, Collector<Result> out) {
    Long c = count.value();
    if (c == null) c = 0L;
    count.update(c + 1);
    out.collect(new Result(e.id(), c + 1));
  }
}
// + Kafka source, sink, watermarks,
//   keyBy, checkpoint config, etc.

With StateFun Actors

public class Counter implements StatefulFunction {

  @Persisted
  PersistedValue<Long> count =
      PersistedValue.of("count", Long.class);

  @Override
  public void invoke(Context ctx, Object input) {
    long c = Optional.ofNullable(count.get()).orElse(0L) + 1;
    count.set(c);
    ctx.send(EgressIdentifier.of("results"),
             new Result(ctx.self().id(), c));
  }
}
// Routing, ingress, egress, checkpoints
// declared in module.yaml.

Built for

  •   Real-time fraud detection


    Per-account state, sub-second decisions on Kafka transaction streams.

    Walkthrough

  •   IoT digital twins


    Per-device state, command/control, telemetry rollups at fleet scale.

    Walkthrough

More patterns work the same way — order workflows, payment sagas, polyglot microservices, real-time scoring. The model in Architecture overview is the same in every case: durable per-key state plus exactly-once messaging.

Polyglot SDKs and pluggable I/O

Write functions in whichever language fits the team. Plug into the streaming and storage substrate you already run.

:fontawesome-brands-java:{ .twemoji }   Java SDK
:fontawesome-brands-python:{ .twemoji }   Python SDK
:fontawesome-brands-golang:{ .twemoji }   Go SDK
:fontawesome-brands-js:{ .twemoji }   JavaScript SDK
:simple-apachekafka:{ .twemoji }   Apache Kafka
:simple-amazonaws:{ .twemoji }   AWS Kinesis
:simple-kubernetes:{ .twemoji }   Kubernetes
:material-database:{ .twemoji }   S3 checkpoints

Why this continuation exists

Apache Stateful Functions stopped releasing in October 2024 at version 3.4.0, locked to Flink 1.16 and Java 11. Anyone wanting to run it against modern Flink either pinned old dependencies or vendored their own patches. StateFun Actors is the public, actively maintained continuation — same code, modern stack, no vendor lock-in.

Apache StateFun 3.4.0 StateFun Actors KZM-3.1
Flink runtime 1.16.2 2.2.0
Java baseline 11 21
Maven group org.apache.flink io.github.kzmlabs.flinkstatefun
Kinesis I/O Flink 1.x consumer Restored on Flink 2.x source/sink
K8s release gate None Mandatory kind + Flink Operator + LocalStack
Active CI Inactive after 3.4.0 Dependabot, CodeQL, Scorecard, Trivy
Release cadence Dormant Active (Maven Central + GHCR)

Full migration notes →

What you get

  • Per-key durable state — read and write your function's own state without manually wiring Flink keyed-state primitives.
  • Exactly-once messaging between functions and to/from external systems, riding Flink's checkpointing.
  • Polyglot remote functions — write functions as HTTP endpoints in any language; the runtime owns state and routing.
  • Deployment flexibility — embedded in Flink, co-located with the JobManager, or remote HTTP services scaled independently.
  • Production-grade releases — every version is gated on a real K8s end-to-end run with the Flink Operator, Kafka, S3 checkpoints, and the actual remote-function pod.

At a glance

flowchart LR
    Kafka[Kafka / Kinesis ingress]:::ingress --> Dispatch[StateFun dispatcher]
    Dispatch -->|state-keyed message| Func[Function instance]
    Func -->|invoke| Remote[Remote HTTP endpoint]
    Remote -->|response| Func
    Func -->|emit| Egress[Kafka / Kinesis egress]:::egress
    Func -->|state I/O| State[(RocksDB keyed state<br/>checkpointed to S3)]

    classDef ingress fill:#fef3c7,stroke:#f59e0b,color:#92400e
    classDef egress fill:#dbeafe,stroke:#2563eb,color:#1e3a8a

Read the architecture overview →

Already running Apache StateFun?

Most user code keeps working unchanged. The only required change is the Maven coordinate: org.apache.flink:statefun-*io.github.kzmlabs.flinkstatefun:statefun-*. Full migration notes in the upstream comparison.

Project status and security

Releases are signed via Sigstore keyless attestation, scanned with Trivy, and tracked by OpenSSF Scorecard. Container images carry SLSA build provenance.

Verify a release artifact with the GitHub CLI:

gh attestation verify oci://ghcr.io/kzmlabs/flink-statefun:3.4.0-KZM-3.1 --owner kzmlabs

Where next

If you want to… Go to
Run StateFun locally and send a test message Quickstart
Add the dependency to your project Install
Build the project from source Building from source
See real-time fraud detection end-to-end Fraud detection example
See an IoT digital-twin system end-to-end IoT fleet example
Wire up Kafka ingress and egress Kafka I/O guide
Wire up Kinesis ingress and egress Kinesis I/O guide
Deploy on a real Kubernetes cluster K8s deployment guide
Understand how Protobuf shading works Architecture / shading
Migrate from Apache Stateful Functions Differences from upstream
Cut a new release Release process