clients
Generated page
Model gemma-mtp, commit ef58254ca7be, 2026-08-16, sources: 6. Edit the code or the hand-written documentation instead.
What this module is responsible for
The clients module provides a suite of client libraries for the booblik protocol, ensuring that various programming languages can interact with the broker as both producers and consumers.
Diagram
Client Implementations
The module provides six client libraries, five of which are reimplementations of the protocol and one which is a multiplatform target (README.md:21). All six libraries are designed to act as both producer and consumer, and all six must pass the same fourteen conformance checks (README.md:6-7).
| Language | Coordinate | Roles | Dependencies |
|---|---|---|---|
| Go | github.com/youndie/booblik/clients/go | producer, consumer | none |
| Python | booblik on PyPI | producer, consumer | none |
| Python-asyncio | booblik.aio | producer, consumer | none |
| Node.js | booblik on npm | producer, consumer | none |
| .NET | Booblik on NuGet | producer, consumer | xunit (tests) |
| Java | booblik-java on reposilite | producer, consumer | JUnit (tests) |
| Kotlin/Native | booblik-native on reposilite | producer, consumer | none |
Kotlin/Native Multiplatform Target
Unlike the other clients, the Kotlin/Native client is not a reimplementation but a target of the shared booblik-protocol (README.md:5-8). It shares the codec, the IDs, and the partitioner with the JVM client, allowing it to compile for both linuxX64 and macosArm64 from a single source (README.md:22-23).
More: Kotlin/Native Multiplatform Target
Batching and Throughput
Performance is heavily dependent on batching; sending one record per request is considered the most expensive mistake possible (README.md:22-23). The broker's measurements show that batches of a hundred can achieve 4,335,482 records/s, compared to only 80,592 records/s when sent one at a time (README.md:23).
Producer and Consumer Mechanics
In the .NET implementation, a Producer owns its Connection and acts as the sole writer to the socket; using the same Connection directly while a Producer is active can lead to mismatched responses (README.md:44-45). For reading, the .NET client uses IAsyncEnumerable to provide back-pressure, ensuring the next fetch does not occur until the current loop body is finished (README.md:81-82).
More: Producer and Consumer Mechanics
CRC-32C Checksum Implementation
Checksum verification requires handling language-specific "traps" regarding integer types and hardware instructions (README.md:37-40).
| Language | Implementation Detail |
|---|---|
| Go | Uses standard library with hardware instruction (README.md:42-43) |
| Python | Requires reading the stored sum as unsigned (README.md:51) |
| JavaScript | Requires >>> 0 because bitwise operators produce signed 32-bit results (README.md:51) |
| Java | Requires a cast from CRC32C.getValue()'s long (README.md:52) |
| C# | Uses unchecked because FNV-1a arithmetic must wrap at 32 bits (README.md:65-66) |
| Kotlin/Native | Uses a reflected polynomial in a 256-entry table (README.md:77-78) |
More: CRC-32C Checksum Implementation
Conformance and Gatekeeping
Each client directory must contain gate.sh for ecosystem-specific checks and conformance-client.sh to execute the client under test (README.md:79-80). The conformance-client.sh script for .NET builds the assembly only if the source files are newer than the existing DLL (conformance-client.sh:13-14).
Key files
| File | Lines | What is there |
|---|---|---|
clients/README.md | 13-19 | Table of client coordinates, roles, and dependencies |
…/dotnet/README.md | 20-42 | Documentation on batching and the Producer class |
…/dotnet/gate.sh | 22-23 | Command to run dotnet test |
…/kotlin-native/README.md | 28-31 | Explanation of the synchronous nature of the Native client |
…/kotlin-native/conformance-client.sh | 18-31 | Logic to select the correct TARGET and LINK_TASK based on the host OS |
Behaviour that surprise
AckPolicy.Nonein .NET results in nothing being returned at all, as no offset exists until the writer reaches the batch (README.md:51-52).- The
keyis never actually sent to the broker; the client calculates the partition and sends the number instead (README.md:55-56). PartitionFor(null)in both .NET and Kotlin/Native advances a round-robin counter, meaning the first call and the subsequent send constitute two turns of the counter (README.md:62andREADME.md:95).