Skip to content

feat(connectors): add Apache Fluss sink connector #3689

Description

@ryerraguntla

Description

Add a sink connector that consumes messages from Iggy topics and writes them into Apache Fluss tables.
Fluss provides durable, offset-ordered log tables and primary-key tables with sub-millisecond lookups and lakehouse tiering. The official Rust client (fluss-rs) speaks Apache Arrow natively, which pairs well with JSON/Avro payloads on the Iggy side and Arrow-oriented egress (for example Iceberg).

Use cases:

  • Land Iggy stream data into Fluss as the real-time analytics / serving layer.
  • Feed Fluss hot tier from Iggy connectors pipelines (sources → transforms → Fluss).
  • Use Fluss PK tables for materialized views keyed by business identifiers from Iggy events.

Affected area / component

  • Connectors (new fluss_sink plugin under core/connectors/sinks/)
  • Connectors runtime configuration examples
  • Integration tests (optional follow-up; may need Fluss test fixture)

Affected area / component

No response

Proposed solution

Implement iggy_connector_fluss_sink as a cdylib plugin implementing iggy_connector_sdk::Sink, following conventions from postgres_sink and iceberg_sink.

Client dependency

Use fluss-rs. Pin a released version in the workspace Cargo.toml when adding the crate.

Write modes (phased)

Phase Fluss table type Write API Iggy input
1 Log table AppendWriter / Arrow RecordBatch append Schema::Json (row objects)
1b Log table Arrow IPC Schema::Raw passthrough Zero-copy when upstream sends Arrow batches
2 Primary-key table UpsertWriter upsert/delete JSON with PK columns + optional op header

Message mapping

  • JSON payloads: map object fields to GenericRow using Fluss table schema (fail batch on type mismatch; log and skip or dead-letter per existing sink patterns).
  • Avro payloads: optional transform via existing avro_convert before write.
  • Arrow IPC (Schema::Raw): decode to RecordBatch and call Fluss batch append API when payload_format = "arrow_ipc".

Routing

Phase 1: single destination (database, table) from config.

Phase 2 (optional): static or dynamic routing by message field (same pattern as iceberg_sink dynamic_route_field).

Example configuration

[plugin_config]
bootstrap_servers = "localhost:9123"
database = "mydb"
table = "events"
table_type = "log"           # "log" | "primary_key"
write_mode = "append"        # "append" | "upsert" | "delete"
payload_format = "json"      # "json" | "arrow_ipc"
batch_size = 500
flush_interval = "1s"
# primary_key_columns = ["id"]   # required when table_type = "primary_key"
# dynamic_routing = false
# dynamic_route_field = "fluss_table"  # "database.table"

Files / layout (expected)

core/connectors/sinks/fluss_sink/
├── Cargo.toml
├── config.toml
├── README.md
└── src/
    ├── lib.rs
    ├── config.rs
    └── writer.rs

Register in workspace Cargo.toml, core/connectors/sinks/README.md, and add a runtime example under core/connectors/runtime/example_config/connectors/.

Example plugins

  • Sink lifecycle / batch consume: postgres_sink, mongodb_sink
  • JSON → typed row mapping: postgres_sink
  • Arrow batch path: iceberg_sink (arrow_json / RecordBatch)

Acceptance criteria

  • fluss_sink plugin builds as cdylib and loads in connectors runtime
  • Consumes Iggy topic batches and appends to configured Fluss log table
  • JSON payload mapping covered by unit tests; integration test or documented manual test plan against local Fluss cluster
  • Transient Fluss errors map to retryable Error variants; permanent schema errors fail fast
  • Config documented in plugin README.md with minimal runnable example
  • cargo fmt, cargo sort --no-format, cargo clippy, cargo test -p iggy_connector_fluss_sink pass

References

Alternatives considered

Alternatives considered

  1. Write via Flink Table API only — excludes Iggy-native connector users.
  2. Iceberg sink only — Fluss hot tier + PK lookup is a different latency/consistency profile than object-store lake tables.
  3. Custom Protobuf client — duplicate of maintained fluss-rs; avoid.

Contribution

  • I'm willing to submit a pull request to implement this feature

Good first issue

  • I think this could be a good first issue for a new contributor

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    connectorsConnectors runtimeenhancementA change that improves our (or users) QoLrustPull requests that update Rust code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions