github ClickHouse/clickhouse-connect v0.12.0rc1

pre-release10 hours ago

Native Async Client (Pre-release)

This is a pre-release for testing and feedback on the new native async client built on aiohttp. Closes #141.

If you're using the sync client and have been looking for a reason to go async, this is a good opportunity to give it a shot. If you're already using AsyncClient, this is a drop-in upgrade. The API surface is identical but under the hood it's completely redesigned.

Previously, the AsyncClient was just the sync urllib3 client wrapped in a thread executor. This is a from-scratch async implementation with real async I/O, proper connection pooling, and a pipelined architecture that streams and processes response data concurrently rather than a read-then-parse pattern, providing a potentially significant performance increase depending on your workload. The old executor-based path still works but is now deprecated and will be removed after release candidate testing and benchmarking is completed.

Install

aiohttp is now a required dependency for using the native async client, but its installation is not included by default. To install this release candidate with the required aiohttp for async use, install clickhouse_connect as follows:

pip install clickhouse-connect[async]==0.12.0rc1

Usage

import asyncio

import clickhouse_connect


async def main():
    async with await clickhouse_connect.get_async_client(host="localhost") as client:
        # create a test table
        await client.command(
            "CREATE TABLE IF NOT EXISTS test_example "
            "(id UInt32, name String) "
            "ENGINE MergeTree ORDER BY id"
        )

        # insert
        data = [[1, "foo"], [2, "bar"]]
        await client.insert("test_example", data, column_names=["id", "name"])

        # query
        result = await client.query("SELECT id, name FROM test_example")
        print(result.result_rows)

        # cleanup
        await client.command("DROP TABLE IF EXISTS test_example")


asyncio.run(main())

As you can see, the method names and signatures are the same as the sync client, you just await them. And for users of the the original async client, you don't have to change anything.

Migrating from the previous AsyncClient

If you're creating your async client like this, you're already on the new native implementation and no changes are needed:

client = await clickhouse_connect.get_async_client(host="localhost")

The only case where you'll still get the old executor-based wrapper is if you're explicitly constructing it from a sync client:

from clickhouse_connect.driver import AsyncClient

sync_client = clickhouse_connect.get_client(host="localhost")
async_client = AsyncClient(client=sync_client)  # legacy path, now deprecated

If you're doing this, it will continue to work for a very short time but you'll see a DeprecationWarning. We recommend switching to get_async_client() when you get a chance so that you're using the native async client, not the deprecated executor-based client. The legacy path has been left in temporarily so users can benchmark it against the native version if they desire, as significant unexpected performance degradation would be very helpful feedback before we remove it entirely.

What we're looking for

  • General stability feedback
  • Performance compared to the sync client and legacy async client in your workloads
  • Any issues with connection pooling, streaming, or concurrent usage
  • Edge cases we haven't hit yet

Please report issues on this repo with [async] in the title.

Note

This release also includes everything from v0.11.0 release.

Don't miss a new clickhouse-connect release

NewReleases is sending notifications on new releases.