clink consumer examples¶
A working set of self-contained examples for consumers of the installed
clink library. Every example here is built from this directory alone -
no in-tree clink checkout required, just a system install of clink and
its dependencies.
Prerequisites¶
- clink installed on the system. See the top-level README
for build/install instructions. The short version:
cmake -S /path/to/clink -B build -DCMAKE_INSTALL_PREFIX=/usr/local cmake --build build --parallel 10 sudo cmake --install build - A C++23 compiler and CMake 3.24+.
Build & run¶
Out-of-tree, against the installed package:
cd docs/consumer-examples
cmake -S . -B build # find_package(clink REQUIRED) does the rest
cmake --build build --parallel 10
./build/01_hello_pipeline
./build/02_event_time_tumbling
./build/03_sliding_window_aggregate
./build/04_keyed_process_state
./build/05_interval_join
./build/06_file_io
./build/07_parquet_io
If clink was installed under a non-standard prefix, set CMAKE_PREFIX_PATH
at configure time: cmake -S . -B build -DCMAKE_PREFIX_PATH=/opt/clink.
The plugin example (08_cluster_job_plugin) builds a .so and is gated:
cmake -S . -B build -DCLINK_BUILD_PLUGIN_EXAMPLE=ON
cmake --build build --target 08_cluster_job_plugin --parallel 10
# Then start a coordinator + worker with clink_node and submit with `clink run` - see
# the comment block at the top of 08_cluster_job_plugin.cpp.
The examples¶
| # | File | Concepts covered |
|---|---|---|
| 01 | 01_hello_pipeline.cpp |
The bare-minimum DAG: VectorSource → MapOperator → FilterOperator → FunctionSink. LocalExecutor::run() blocks until the source is drained. |
| 02 | 02_event_time_tumbling.cpp |
Keyed event-time tumbling windows. KeyByOperator partitions by user, TumblingWindowOperator aggregates per (key, window). Source emits Watermark::max() at end-of-stream, flushing all windows. |
| 03 | 03_sliding_window_aggregate.cpp |
Sliding event-time windows. Same shape as #02 but the operator emits each window once per slide; each event contributes to size/slide overlapping windows. |
| 04 | 04_keyed_process_state.cpp |
KeyedProcessFunction + per-key persistent state via RuntimeContext::keyed_state(). Backed by InMemoryStateBackend here; swap to RocksDbStateBackend (linked via clink::rocksdb) for durability. |
| 05 | 05_interval_join.cpp |
Two-stream interval join on a shared key with an event-time window [lower, upper]. Default is inner join; pass a Dag::JoinType::LeftOuter (and friends) for outer joins with watermark-driven emission of unmatched rows. |
| 06 | 06_file_io.cpp |
FileSource<string> + FileSink<string> against a TextFormat<T> codec. Word-count over newline-delimited input, written as TSV. |
| 07 | 07_parquet_io.cpp |
ParquetSink<T> + ParquetSource<T> over the shared ArrowBatcher<T> seam. The resulting file is a vanilla Parquet stream - open it from pyarrow / duckdb / polars to confirm. |
| 08 | 08_cluster_job_plugin.cpp |
Pipeline packaged as a job plugin .so using Pipeline + CLINK_REGISTER_JOB. Submit to a running cluster via clink run. |
| 09 | 09_testing_framework.cpp |
Testing a stateful operator with clink::test_support (the public testing framework): a KeyedProcessFunction driven through make_keyed_process_function_harness, per-key state inspected via the production read path, and a snapshot → restore round trip. Links clink::test_support and registers with CTest (it exits non-zero on failure). |
Picking targets vs. linking everything¶
The CMakeLists in this directory links every example to clink::core
(the engine, no connectors). If your real-world job uses Kafka, Postgres,
or S3, switch to:
target_link_libraries(my_pipeline PRIVATE clink::core clink::kafka)
# or, the kitchen-sink alias:
target_link_libraries(my_pipeline PRIVATE clink::clink)
After find_package(clink REQUIRED), the clink_AVAILABLE_IMPLS
variable holds the semicolon-separated list of impls that were installed
on this machine. Gate optional features on it:
if("kafka" IN_LIST clink_AVAILABLE_IMPLS)
target_compile_definitions(my_pipeline PRIVATE HAS_KAFKA=1)
target_link_libraries(my_pipeline PRIVATE clink::kafka)
endif()
For tests, link clink::test_support alongside clink::core to pull in the
public testing framework (operator harnesses, state inspection, snapshot /
restore, deterministic time) - example 09 shows the pattern.
A lean install without any connectors is available: build clink with
-DCLINK_BUILD_IMPLS=OFF and its clinkConfig requires only Arrow / Parquet /
Threads (no connector SDKs), shipping clink::core, clink::clink and
clink::test_support without the runnable clink_node.
Where to go next¶
include/clink/api/pipeline.hpp- the higher-level fluent builder used by #08. Comparable to
DataStreamAPI. include/clink/runtime/dag.hpp- the lower-level DAG used by #01-#07. Comparable to
StreamGraph. The fluent env lowers to this. docs/internals/architecture.md- engine concepts in more depth (watermarks, checkpoints, state, alignment, …).examples/- additional in-tree examples that are built and run as part of the upstream test suite.state_as_data/- a CLI + Python workflow (not a C++ build target): export a running job's keyed state as Parquet / Iceberg and query it with DuckDB / pyarrow. Shows clink's open state format end to end.