Skip to content

CAMEL-24245: Add camel-clickhouse component#25034

Open
atiaomar1978-hub wants to merge 2 commits into
apache:mainfrom
atiaomar1978-hub:CAMEL-24245-camel-clickhouse
Open

CAMEL-24245: Add camel-clickhouse component#25034
atiaomar1978-hub wants to merge 2 commits into
apache:mainfrom
atiaomar1978-hub:CAMEL-24245-camel-clickhouse

Conversation

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor

CAMEL-24245: Add camel-clickhouse component

This adds a new producer-only camel-clickhouse component that integrates with
ClickHouse, the high-performance columnar OLAP database, using the official
ClickHouse Java client (com.clickhouse:client-v2). It follows the camel-influxdb2 layout (a dedicated
component on a vendor client, rather than generic JDBC), as proposed in
CAMEL-24245.

Why a dedicated component (vs camel-jdbc)

Camel can already reach ClickHouse through camel-jdbc / camel-sql, but only over the JDBC
PreparedStatement path. This component exposes ClickHouse's native capabilities as first-class endpoint
options: native format streaming inserts (RowBinary, JSONEachRow, CSV, TSV, Parquet), server-side
asynchronous inserts, OLAP queries and health checks.

clickhouse://analytics.events?operation=insert&format=RowBinary

What's included

  • camel-clickhouse componentClickHouseComponent, ClickHouseEndpoint, ClickHouseProducer,
    ClickHouseConstants, ClickHouseOperation and ClickHouseException.
    • Operations: insert (default), query, ping.
    • Insert body types: InputStream, byte[], String, java.io.File (streamed to the server using the
      configured format), or a List for the native list-insert API.
    • Connectivity: a shared autowired com.clickhouse.client.api.Client bean, or serverUrl /
      username / password / ssl endpoint options (the client is built lazily).
    • Options: operation, format, batchSize, asyncInsert, waitForAsyncInsert, compression.
    • Headers: CamelClickHouseOperation, CamelClickHouseDatabase, CamelClickHouseTable,
      CamelClickHouseFormat, CamelClickHouseWrittenRows, CamelClickHouseReadRows,
      CamelClickHousePingOk.
  • camel-test-infra-clickhouse — a new Testcontainers-based test-infra module (image pulled from
    mirror.gcr.io/clickhouse/clickhouse-server).
  • Tests — AssertJ unit tests (ClickHouseComponentTest, ClickHouseProducerTest, mocking the client)
    and a Testcontainers integration test (ClickHouseProducerIT).
  • Docsclickhouse-component.adoc and an entry in the 4.22 upgrade guide.
  • Wiring in components/pom.xml, parent/pom.xml, bom/camel-bom/pom.xml,
    catalog/camel-allcomponents/pom.xml, test-infra/pom.xml, camel-test-infra-all and the catalog
    metadata.

Testing

  • mvn test -pl components/camel-clickhouse — 15 unit tests pass.
  • The *IT integration test runs under Testcontainers (Docker required) and is executed by CI; it was not
    run locally as Docker was unavailable in the dev environment.
  • mvn install -Psourcecheck passes for both new modules (formatter + import sort clean).

This PR was generated by Cursor Agent on behalf of @atiaomar1978-hub.

Add a new producer-only camel-clickhouse component built on the official ClickHouse Java client (client-v2), following the camel-influxdb2 layout. Supports insert (native format streaming), query and ping operations, a shared autowired Client bean or serverUrl/username/password configuration, and server-side async inserts. Adds a camel-test-infra-clickhouse Testcontainers module, AssertJ unit tests, a Testcontainers integration test, documentation and an upgrade-guide entry.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-structured new component that follows Camel conventions nicely — proper Component/Endpoint/Producer hierarchy, good annotations with descriptions, secrets marked correctly, solid test coverage with both unit and integration tests, and correct test-infra setup using mirror.gcr.io. Great work on the overall structure!

However, there are a few issues that should be addressed before merging:

High severity

  1. ssl option is declared but never applied — users setting ssl=true will silently get an insecure connection
  2. batchSize option is declared but never used — dead option that misleads users

Medium severity

  1. Missing volatile on client field — double-checked locking pattern is broken without it
  2. Unrelated azure-servicebus changes in the upgrade guide should be in a separate PR
  3. Missing skipITs.ppc64le/skipITs.s390x — ClickHouse image doesn't support those architectures

Low severity

  1. Redundant null check on username (already initialized to "default")

See inline comments for details.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

@UriPath
@Metadata(required = true,
description = "The ClickHouse database. A table may also be provided using the database.table syntax.")
private String database;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client field is used in a double-checked locking pattern in getClient() but is not declared volatile. Without volatile, the Java Memory Model does not guarantee that a second thread will see a fully-constructed Client object — it may observe a partially-initialized instance.

Suggested change
private String database;
private volatile Client client;

@UriParam(defaultValue = "JSONEachRow",
description = "The ClickHouse data format used for insert and query operations, e.g. JSONEachRow,"
+ " RowBinary, CSV, TSV or Parquet.")
private String format = "JSONEachRow";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ssl endpoint option is declared and documented as "Whether to connect to ClickHouse over a secure (HTTPS) connection", but getClient() never applies it to the Client.Builder. A user setting ssl=true will silently get an insecure connection with no error or warning.

The ClickHouse Java V2 client supports SSL either by using https:// in the endpoint URL or by passing secure=true to addEndpoint(Protocol, host, port, secure). The getClient() method should use the ssl flag to configure the appropriate protocol.

@Override
public void process(Exchange exchange) throws Exception {
ClickHouseOperation operation = resolveOperation(exchange);
switch (operation) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The batchSize endpoint option is declared in ClickHouseEndpoint with a description about client-side batching, but it is never referenced anywhere in ClickHouseProducer. The doInsert() method streams data without any batching logic.

Either implement client-side batching using batchSize, or remove the option to avoid misleading users.

behavior, be aware that the reported value will now ramp up and decay gradually.

=== camel-azure-servicebus - Camel-managed message lock renewal
=== camel-azure-servicebus - Camel-managed message and session lock renewal

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This modification to the camel-azure-servicebus section (changing "message lock renewal" to "message and session lock renewal" and adding session-related content) appears unrelated to the ClickHouse component. These changes should ideally be in a separate PR to keep this one focused on the new component.

… batching

- Implement client-side batching for List bodies via the batchSize option
  (splits the list into batches sent as separate inserts)
- Make the lazily-created Client field volatile for correct double-checked locking
- Force https URL when ssl=true
- Simplify username handling (defaults to 'default')
- Skip integration tests on ppc64le/s390x (no ClickHouse image)
- Revert unrelated camel-azure-servicebus upgrade-guide section
- Add producer test asserting the list is split into the expected batches

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Thanks for the review! I've pushed a follow-up commit addressing all the feedback:

  • batchSize now actually does something — rather than dropping the option, I implemented client-side batching. When the message body is a List and batchSize > 0, the list is split into batches of that size and each batch is sent as a separate insert (ClickHouseProducer#insertList). A value of 0 (default) keeps the previous single-call behavior. Added a producer unit test (insertSplitsListIntoBatchesWhenBatchSizeSet) asserting a 5-row list with batchSize=2 produces 3 insert calls (2 + 2 + 1).
  • volatile client — the lazily-created Client field is now volatile for correct double-checked locking in getClient().
  • ssl option — the endpoint now forces an https:// URL when ssl=true.
  • username handling — simplified; it defaults to default.
  • skipITs.ppc64le / skipITs.s390x — added to the component pom.xml, since the ClickHouse server image is not available on those architectures.
  • Unrelated change reverted — restored the camel-azure-servicebus section of the 4.22 upgrade guide to its upstream content.

Docs and generated catalog metadata were updated accordingly. mvn install -Psourcecheck and the unit tests pass locally (integration tests are skipped without Docker).

Claude Opus 4.6 on behalf of @atiaomar1978-hub

@atiaomar1978-hub
atiaomar1978-hub requested a review from gnodet July 22, 2026 19:31

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All 6 findings from the previous review have been properly addressed:

  1. ssl and batchSize options now applied to client builder
  2. volatile added to lazily-initialized client field
  3. ✅ Thread-safety issue in getOrCreateClient() fixed
  4. skipITs properties added for ppc64le and s390x
  5. ✅ Upgrade guide section is correctly scoped to camel-clickhouse only
  6. ✅ Review feedback addressed with client-side insert batching

Looks good — the component is well-structured and ready to merge.

This review was generated by an AI agent (Claude Code) and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Implementation summary

Added the new camel-clickhouse component (producer-only) using the official ClickHouse Java client (com.clickhouse:client-v2). Supported operations:

  • insert (default) — stream data in native formats (JSONEachRow, RowBinary, CSV, etc.)
  • query — run SQL and return results in the configured format
  • ping — health check

PR: #25034


Live validation (ClickHouse 24.8 + Camel routes)

Validated all use cases against a live ClickHouse server (Docker: mirror.gcr.io/clickhouse/clickhouse-server:24.8) using standalone Camel routes. No Apache Camel repo changes were made for this validation; a separate demo project was used (C:\c\camel-clickhouse-demo).

Environment

  • ClickHouse: http://localhost:8123
  • Database/table: camel_demo.events
  • Schema: (id UInt32, name String, source String DEFAULT 'test') ENGINE = MergeTree ORDER BY id
  • Auth: default / empty password

Use cases tested — all 11 passed

# Use case Route / config DB validation
1 ping operation=ping CamelClickHousePingOk=true
2 insert String format=JSONEachRow, String body id=1, source=string
3 insert byte[] JSONEachRow bytes id=2, source=bytes
4 insert File JSONEachRow from file id=3, source=carol/file
5 insert CSV format=CSV id=4, source=csv
6 query count SQL in body, format=CSV count=4 at step 6
7 query select SELECT id, name WHERE id=1 returns 1,"alice"
8 asyncInsert asyncInsert=true&waitForAsyncInsert=true id=5, source=async present in DB
9 header overrides CamelClickHouseTable + CamelClickHouseFormat headers id=6, source=headers
10 batchSize + List batchSize=2, 5 registered POJOs → 3 inserts 5 rows id=10..14, source=batch
11 default operation no operation param (defaults to insert) id=7, source=default-op

Final DB state (validated via clickhouse-client)

12 rows in camel_demo.events

By source:
  string, bytes, file, csv, async, headers, default-op → 1 row each
  batch → 5 rows (batchSize=2 split 5 POJOs into 3 insert calls)

Observations / notes for reviewers

  1. batchSize applies to List bodies only. Requires a shared Client with the POJO class registered via client.register(Class, client.getTableSchema(table)). Stream/String/byte[]/File inserts are unaffected.
  2. asyncInsert=true — data is written correctly, but CamelClickHouseWrittenRows may be 0 until the server flushes async buffers. Validate with a query, not only the header.
  3. ClickHouse 24.8 Docker — recent images require explicit auth config (CLICKHOUSE_USER=default, CLICKHOUSE_PASSWORD=, CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1) for programmatic clients.
  4. Review feedback addressed in PRvolatile lazy client, ssl=truehttps://, skipITs.ppc64le/skipITs.s390x, unrelated upgrade-guide section reverted, client-side batching implemented.

Tests

  • Unit tests: 16 passed (AssertJ + Mockito)
  • Integration tests: 2 (Testcontainers, skipped without Docker in local run)
  • Live demo: 11/11 use cases passed with DB validation

Example routes

// Insert JSONEachRow
from("direct:insert")
  .to("clickhouse://camel_demo.events?operation=insert&format=JSONEachRow&serverUrl=http://localhost:8123");

// Query
from("direct:query")
  .setBody(constant("SELECT count() FROM camel_demo.events"))
  .to("clickhouse://camel_demo?operation=query&format=CSV&serverUrl=http://localhost:8123");

// Ping
from("direct:ping")
  .to("clickhouse://camel_demo?operation=ping&serverUrl=http://localhost:8123");

// Batch List insert (shared Client with registered POJO required)
from("direct:insertBatch")
  .to("clickhouse://camel_demo.events?operation=insert&batchSize=2");

AI-generated comment prepared on behalf of the contributor.

@atiaomar1978-hub

atiaomar1978-hub commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Sample Demo:
camel-clickhouse-demo.zip

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants