Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
a96ea7f
Add performance test suite running on a self-hosted runner
astubbs Apr 11, 2026
62f9f15
docs(agents): document -Dlicense.skip and when to use it
astubbs Apr 11, 2026
cc26d3f
ci: restructure PR builds into 4 tiers for faster feedback
astubbs Apr 14, 2026
9736710
ci: restrict push builds to master branch only
astubbs Apr 14, 2026
34f0ead
ci: add surefire rerun for flaky tests in Tier 1 and Tier 2
astubbs Apr 14, 2026
21b94da
ci: simplify to single Build & Test then fan out matrix + performance
astubbs Apr 14, 2026
2ad99ca
ci: use ci-build.sh for Build & Test, add perf exclusion and flaky rerun
astubbs Apr 14, 2026
32a66aa
ci: use bin/performance-test.sh for performance job
astubbs Apr 14, 2026
d5fe62a
ci: add experimental Kafka 4.x to PR matrix (non-blocking)
astubbs Apr 14, 2026
50d024c
docs: remove SELF_HOSTED_RUNNER.md (not used atm)
github-actions[bot] Apr 14, 2026
7984990
ci: skip claude code review on bot-triggered events
astubbs Apr 14, 2026
2419762
fix: match TestContainers broker version to Kafka client version
astubbs Apr 14, 2026
a35fc15
fix: handle null epoch when poll returns records before onPartitionsA…
astubbs Apr 14, 2026
d284c41
ci: drop Kafka 2.8.1 from matrix — EOL, no longer supported
astubbs Apr 15, 2026
7bf5850
ci: run unit, integration, performance in parallel with fail-fast
astubbs Apr 15, 2026
f894441
ci: remove redundant kafka-matrix from PR builds
astubbs Apr 15, 2026
66038eb
ci: add Codecov coverage tracking with drop prevention
astubbs Apr 15, 2026
6c5fee1
ci: add CODECOV_TOKEN for branch-protected repos, document in AGENTS.md
astubbs Apr 15, 2026
9004cde
ci: add JaCoCo integration test coverage reporting
astubbs Apr 15, 2026
b58e3c2
ci: add jscpd duplicate code detection to PR builds
astubbs Apr 15, 2026
2833726
ci: add SpotBugs, dependency vulnerability scanning, and PIT mutation…
astubbs Apr 15, 2026
1f4816d
ci: fix SpotBugs to core module only, make dependency scan non-blocking
astubbs Apr 15, 2026
94ba855
ci: use build scripts for all CI jobs, add timeouts, restore all modules
astubbs Apr 15, 2026
cdfd23e
ci: add PR comments for duplicate detection, SpotBugs, and PIT reports
astubbs Apr 15, 2026
c7d27ce
ci: fix PIT reactor convergence (-am flag) and glob dependency in script
astubbs Apr 15, 2026
8b76f1f
ci: replace ossindex with GitHub dependency-review-action
astubbs Apr 15, 2026
e273d69
ci: re-trigger after enabling dependency graph in repo settings
astubbs Apr 15, 2026
5178b5d
fix: VertxConcurrencyIT stall on CI - increase wait, add timeout, pro…
astubbs Apr 16, 2026
a26964b
docs: consolidate all agent rules into AGENTS.md
astubbs Apr 16, 2026
d8399bb
Apply suggestions from code review
astubbs Apr 16, 2026
1e9b828
ci: fix duplicate permissions block from Copilot Autofix suggestion
astubbs Apr 16, 2026
1071961
ci: add base-vs-PR duplicate comparison with increase detection
astubbs Apr 16, 2026
2d6933e
ci: extract duplicate report to script, add PR annotations for new cl…
astubbs Apr 16, 2026
9bda20a
ci: tighten duplicate increase tolerance from 0.5% to 0.1%
astubbs Apr 16, 2026
9def3fd
ci: fix clone comparison to use content hash, remove full clone list
astubbs Apr 16, 2026
d235e67
ci: add file similarity check using duplicate-code-detection-tool
astubbs Apr 16, 2026
8aa7241
ci: re-trigger after fixing file similarity JSON parsing
astubbs Apr 16, 2026
90f2fe5
ci: switch duplicate code detection from jscpd to PMD CPD
astubbs Apr 16, 2026
1a4a4fd
ci: raise PMD CPD duplication threshold from 3% to 5%
astubbs Apr 16, 2026
9e6651b
ci: combine PMD CPD and jscpd into single duplicate check with merged…
astubbs Apr 16, 2026
2d29148
ci: add expressive emoji reactions for duplicate delta changes
astubbs Apr 16, 2026
5434995
ci: migrate to astubbs/duplicate-code-cross-check action
astubbs Apr 16, 2026
ef6f919
ci: pin duplicate-code-cross-check to @v1 instead of @main
astubbs Apr 16, 2026
bf755eb
ci: re-trigger to pick up cached Maven deps from prior partial run
astubbs Apr 16, 2026
2ddb47a
ci: add prepare-deps job to pre-warm Maven cache
astubbs Apr 16, 2026
bb2ad8a
ci: right-size job timeouts based on observed data
astubbs Apr 16, 2026
80d7e00
ci: fix CI hangs by fixing repo order and adding Maven connection tim…
astubbs Apr 16, 2026
4a9f7a0
ci: strip comments from .mvn/maven.config
astubbs Apr 16, 2026
617d5db
ci: fix PIT silent failures and exclude flaky test from baseline
astubbs Apr 16, 2026
328e39f
ci: bump Maven read timeout and fix Awaitility state leak between tests
astubbs Apr 16, 2026
3535620
ci: fix stale Maven cache, bump timeout to 120s, re-exclude flaky PIT…
astubbs Apr 16, 2026
096442d
ci: exclude PCMetricsTest from PIT baseline + track fix in issue #39
astubbs Apr 16, 2026
dce4d5d
test: fix the four PIT baseline-failing tests at their source
astubbs Apr 16, 2026
6627a77
test: bump SASL retry budget 25s→60s for PIT JVM headroom
astubbs Apr 16, 2026
b176444
test: shrink SASL test windows 20s→8s to fit PIT baseline budget
astubbs Apr 16, 2026
21be77b
ci: re-exclude only MockConsumerTestWithSaslAuthenticationException f…
astubbs Apr 16, 2026
368319d
ci: also re-exclude PCMetricsTest from PIT baseline
astubbs Apr 16, 2026
5d9f022
test: root-cause the PIT ~85s "cliff" — leaked non-daemon threads
astubbs Apr 17, 2026
a51b712
ci: drop PIT exclusions now that the leaked-thread root cause is fixed
astubbs Apr 17, 2026
475e1b8
test: fix flaky PartitionOrderProcessingTest race condition
astubbs Apr 17, 2026
6fa9c3c
ci: strip Jacoco from PIT minions to fix PCMetricsTest on CI
astubbs Apr 17, 2026
0a9623f
ci: bump PIT timeout 15m → 60m to let mutation phase complete
astubbs Apr 17, 2026
0b579a3
ci: fix PIT mutation-phase timeouts with generous timeout knobs
astubbs Apr 17, 2026
27fcf78
ci: make PIT non-blocking (continue-on-error) + 24h timeout
astubbs Apr 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,7 @@ on:

jobs:
claude-review:
# Optional: Filter by PR author
# if: |
# github.event.pull_request.user.login == 'external-contributor' ||
# github.event.pull_request.user.login == 'new-developer' ||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'

if: github.event.sender.type != 'Bot'
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
346 changes: 270 additions & 76 deletions .github/workflows/maven.yml

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions .github/workflows/performance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Performance test suite, run on a self-hosted Windows runner with Docker Desktop.
#
# These tests are tagged @Tag("performance") and excluded from the regular CI
# build because they need substantial hardware (CPU, memory, disk). They run
# on dedicated machines where the user has labelled their runner with the
# "performance" custom label.
#
# Triggers:
# - workflow_dispatch (manual) - primary trigger
# - schedule (weekly) - automated regression check
# - NOT on PRs from forks - self-hosted runners + untrusted code = bad
#
# See docs/SELF_HOSTED_RUNNER.md for one-time runner setup instructions.

name: Performance Tests

on:
workflow_dispatch:
inputs:
kafka_version:
description: 'Kafka version to test against (default: project default)'
required: false
type: string
default: ''
schedule:
# Weekly on Sunday at 02:00 UTC
- cron: '0 2 * * 0'

concurrency:
# Only run one performance test at a time per branch - they're slow and resource-heavy
group: performance-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: read

jobs:
performance:
name: "Performance suite (self-hosted)"
# Targets a self-hosted runner labelled "performance" running Windows.
# The "self-hosted" label is automatic; "windows" and "performance" are
# added when the runner is registered. See docs/SELF_HOSTED_RUNNER.md.
runs-on: [self-hosted, windows, performance]
timeout-minutes: 180

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup JDK 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
# Don't cache here - self-hosted runners persist .m2 across runs already
cache: ''

- name: Show environment
shell: cmd
run: |
java -version
docker --version
docker info

- name: Run performance tests
shell: cmd
env:
KAFKA_VERSION: ${{ inputs.kafka_version }}
run: |
if defined KAFKA_VERSION (
call bin\performance-test.cmd -Dkafka.version=%KAFKA_VERSION%
) else (
call bin\performance-test.cmd
)

- name: Upload test reports
if: always()
uses: actions/upload-artifact@v7
with:
name: performance-reports-${{ github.run_number }}
path: '**/target/*-reports/*.xml'
retention-days: 30
6 changes: 6 additions & 0 deletions .mvn/maven.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-Dmaven.wagon.http.connectionTimeout=10000
-Dmaven.wagon.http.readTimeout=120000
-Dmaven.wagon.httpconnectionManager.ttlSeconds=120
-Dmaven.wagon.http.retryHandler.count=3
-Daether.connector.connectTimeout=10000
-Daether.connector.requestTimeout=120000
98 changes: 95 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ bin/ci-build.sh 3.9.1
- **Integration tests**: `mvn verify` / failsafe plugin. Source in `src/test-integration/java/`. Uses TestContainers with `confluentinc/cp-kafka` Docker image.
- **Test exclusion patterns**: `**/integrationTest*/**/*.java` and `**/*IT.java` are excluded from surefire, included in failsafe.
- **Kafka version matrix**: CI tests against multiple Kafka versions via `-Dkafka.version=X.Y.Z`.
- **Performance tests**: Tagged `@Tag("performance")` and excluded from regular CI by default. They run on a self-hosted runner via `.github/workflows/performance.yml` (see `docs/SELF_HOSTED_RUNNER.md`). Run locally with `bin/performance-test.sh` (or `bin/performance-test.cmd` on Windows). Override the test group selection with Maven properties: `-Dincluded.groups=performance` to run only perf, `-Dexcluded.groups=` to run everything.

## Known Issues

Expand All @@ -56,10 +57,101 @@ bin/ci-build.sh 3.9.1

- **Lombok**: Used extensively (builders, getters, logging). IntelliJ Lombok plugin required.
- **EditorConfig**: Enforced via `.editorconfig` - 4-space indent for Java, 120 char line length.
- **License headers**: Managed by `license-maven-plugin` (Mycila). Use `-Dlicense.skip` locally to skip checks.
- **License headers**: Managed by `license-maven-plugin` (Mycila). See "License headers" section below.
- **Google Truth**: Used for test assertions alongside JUnit 5 and Mockito.

## License headers

The Mycila `license-maven-plugin` enforces a Confluent copyright header on all source files. It uses git-derived years via `${license.git.copyrightYears}`.

**Skipping the check** (for any Maven goal):
```
./mvnw <goal> -Dlicense.skip
```

**When to skip:**
- Running builds inside a git worktree — the git-years lookup fails with `Bare Repository has neither a working tree, nor an index`
- Local iteration where you don't want years auto-bumped on touched files
- Any command other than the canonical `mvn install` flow when copyright drift would create noise in `git status`

The default behavior on macOS dev machines is `format` mode (auto-fixes headers) via the `license-format` profile (auto-activated). The `ci` profile flips this to `check` mode (fails the build on drift). Both `bin/build.sh` and `bin/ci-build.sh` already pass `-Dlicense.skip` for this reason.

**When NOT to skip:**
- You're intentionally running `mvn license:format` to update headers
- You want to verify CI's check would pass before pushing

## Agent Rules

### Git Safety
- **NEVER commit or push without explicitly asking the user first.** Wait for approval. This is the #1 rule.
- **When creating a stacked PR, include `depends on #N` in the PR description** (where `#N` is the parent PR it stacks on). This fork runs a PR dependency gating action (see `.github/workflows/check-dependencies.yml`) which blocks child PRs from merging until the parent is merged. One `depends on` line per parent. Keep the list accurate if the chain changes.
- Branch off master for upstream contributor cherry-picks so PRs show only their change.
- Never commit without tests and documentation in the same pass.
- Run tests before committing. If they fail, fix them first.
- When you fix something or finish implementing something, record what lessons you learnt.

### Development Discipline
- **Skateboard first.** Build the simplest end-to-end thing that works. Before starting a feature, ask: "Is this blocking the next public milestone?" If not, flag it and move on.
- **Never paper over the real problem** - make the proper fix.
- Don't propose workarounds that require user action when the software can solve it. If the software has enough information to derive the right answer, it should just do it.
- If constructing data in memory that is eventually going to be saved, save it as soon as it's created. Don't delay in case the programme crashes or the user exits.

### Code Quality
- **Be DRY.** Reuse existing functions. Don't copy code - refactor where necessary. Refactor out common patterns.
- Never weaken test assertions - classify exceptions instead of ignoring them.
- Wire components through PCModule DI - don't bypass the dependency injection system.
- Validate user input - don't let bad input cause silent failures.
- Handle errors visibly - don't swallow exceptions.
- Give things meaningful names that describe what they do. Never use random or generic names.

### Test Discipline
- Search for existing test harnesses and utilities before creating new ones.
- Run the complete test suite periodically, not just targeted tests.
- Maintain good high-level test coverage. Only get detailed on particularly complex functions that benefit from fine-grained testing.

### CI and Automation
- Always set up continuous integration, code coverage, and automated dependency checking.
- Make scripts for common end-user requirements with helpful, suggestive CLI interfaces.

### Documentation
- Keep a diary of major plans and their milestones.
- **Keep a developer-facing product specification** that outlines product features, functionality, and implementation architecture - separately from end-user documentation. With agentic programming, the developer can lose sight of architecture and implementation details. This document exposes the interesting, novel, and important implementation decisions so the developer maintains a clear mental model of the system even when agents are doing most of the coding.
- Keep end-user documentation updated.
- Keep documentation tables of contents updated.

### Communication
- Use precise terminology - if the project defines specific terms, use them consistently. Don't use ambiguous words.
- Don't write with em dash characters.

### Rule Sync
- Keep this AGENTS.md in sync with any global CLAUDE.md rules. If you have rules in your global config that are missing here, suggest to the user that they be added. This ensures all contributors and agents working on this project follow the same standards.

### Working Directory
- Always run commands from the project root directory.
- Use `./mvnw` or `bin/*.sh` scripts - don't cd into submodules.
- Use `-pl module-name -am` for module-specific builds.

## CI

- **GitHub Actions**: `.github/workflows/maven.yml` - runs on push/PR to master with Kafka version matrix.
- **Semaphore** (Confluent internal): `.semaphore/semaphore.yml` - primary CI for upstream.
PR builds run these jobs in parallel (fail-fast cancels others if any fails):

| Job | Script / Tool | Purpose |
|-----|--------------|---------|
| **Unit Tests** | `bin/ci-unit-test.sh` | Surefire tests, no Docker |
| **Integration Tests** | `bin/ci-integration-test.sh` | Failsafe tests, TestContainers |
| **Performance Tests** | `bin/performance-test.sh` | `@Tag("performance")` volume tests |
| **SpotBugs** | Maven spotbugs plugin | Static analysis for bugs |
| **Duplicate Code Check** | PMD CPD | Detect Java copy-paste blocks (base-vs-PR comparison) |
| **Dependency Vulnerabilities** | GitHub dependency-review-action | CVE scanning |
| **Mutation Testing (PIT)** | pitest-maven | Test quality verification |

Push builds (master): Full Kafka version matrix (3.1.0, 3.7.0, 3.9.1 + experimental [3.9.1,5) for 4.x).

- **Code coverage**: JaCoCo → [Codecov](https://app.codecov.io/gh/astubbs/parallel-consumer). PRs fail if overall coverage drops by more than 1%.
- **Semaphore** (Confluent internal): `.semaphore/semaphore.yml` — primary CI for upstream.

### Required secrets

| Secret | Purpose |
|--------|---------|
| `CODECOV_TOKEN` | Codecov upload token — required because branch protection is enabled. Get it from [Codecov settings](https://app.codecov.io/gh/astubbs/parallel-consumer/settings). |
55 changes: 54 additions & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ The user just has to provide a function to extract from the message the HTTP cal

=== Illustrative Performance Example

.(see link:./parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VolumeTests.java[VolumeTests.java])
.(see link:./parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java[VeryLargeMessageVolumeTest.java])
These performance comparison results below, even though are based on real performance measurement results, are for illustrative purposes.
To see how the performance of the tool is related to instance counts, partition counts, key distribution and how it would relate to the vanilla client.
Actual results will vary wildly depending upon the setup being deployed into.
Expand Down Expand Up @@ -1341,6 +1341,59 @@ Note::
See https://github.com/confluentinc/parallel-consumer/issues/162[issue #162]
and this https://stackoverflow.com/questions/4786881/why-is-test-jar-dependency-required-for-mvn-compile[Stack Overflow question].

=== Build Scripts

Helper scripts are in the `bin/` directory:

[qanda]
Quick local build (compile + unit tests)::
`bin/build.sh`

Unit tests only (no Docker needed)::
`bin/ci-unit-test.sh`

Integration tests only (requires Docker for TestContainers)::
`bin/ci-integration-test.sh`

Full CI build with all tests (unit + integration)::
`bin/ci-build.sh`

CI build against a specific Kafka version::
`bin/ci-build.sh 3.9.1`

Performance test suite (also `bin/performance-test.cmd` on Windows)::
`bin/performance-test.sh`

All `ci-*` scripts use the `-Pci` Maven profile which enables license checking and disables parallel test execution. The GitHub Actions CI workflow uses these scripts, so running them locally reproduces the CI environment.

=== Performance Tests

Tests tagged `@Tag("performance")` are excluded from the regular CI build because they need substantial hardware. They run on a dedicated self-hosted runner via `.github/workflows/performance.yml` (manual trigger or weekly schedule).

To run the performance suite locally, use `bin/performance-test.sh`. To set up your own self-hosted runner for these tests, see link:./docs/SELF_HOSTED_RUNNER.md[docs/SELF_HOSTED_RUNNER.md].

=== Releasing

The `pom.xml` version is the source of truth for publishing — there is no `maven-release-plugin` step.

On every push to `master`, `.github/workflows/publish.yml` deploys to Maven Central:

* If the version ends in `-SNAPSHOT` → publishes a snapshot
* If the version does not end in `-SNAPSHOT` → publishes a full release, creates a `v<version>` git tag, and creates a GitHub release

To cut a release:

. Open a PR removing `-SNAPSHOT` from `<version>` in the parent `pom.xml` (e.g. `0.6.0.0-SNAPSHOT` → `0.6.0.0`)
. Merge it to master → CI publishes the release
. Open another PR bumping to the next snapshot (e.g. `0.6.0.1-SNAPSHOT`) and merge

Required GitHub repository secrets:

* `MAVEN_CENTRAL_USERNAME` — Sonatype Central Portal token username
* `MAVEN_CENTRAL_PASSWORD` — Sonatype Central Portal token password
* `MAVEN_GPG_PRIVATE_KEY` — Armored GPG private key for signing artifacts
* `MAVEN_GPG_PASSPHRASE` — Passphrase for the GPG key

=== Testing

The project has good automated test coverage, of all features.
Expand Down
4 changes: 3 additions & 1 deletion bin/ci-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ fi
-Pci \
clean verify \
$KAFKA_VERSION_ARG \
-Dlicense.skip
-Dlicense.skip \
-Dexcluded.groups=performance \
-Dsurefire.rerunFailingTestsCount=2
18 changes: 18 additions & 0 deletions bin/ci-integration-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
#
# Copyright (C) 2020-2026 Confluent, Inc.
#

# Run integration tests only (failsafe, requires Docker for TestContainers).
# Skips unit tests to avoid duplicate work.
# Usage: bin/ci-integration-test.sh

set -euo pipefail

./mvnw --batch-mode \
-Pci \
clean verify \
-DskipUTs=true \
-Dlicense.skip \
-Dexcluded.groups=performance \
-Dsurefire.rerunFailingTestsCount=2
16 changes: 16 additions & 0 deletions bin/ci-unit-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
#
# Copyright (C) 2020-2026 Confluent, Inc.
#

# Run unit tests only (surefire, no Docker/TestContainers needed).
# Usage: bin/ci-unit-test.sh

set -euo pipefail

./mvnw --batch-mode \
-Pci \
clean test \
-Dlicense.skip \
-Dexcluded.groups=performance \
-Dsurefire.rerunFailingTestsCount=2
18 changes: 18 additions & 0 deletions bin/performance-test.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@REM Copyright (C) 2020-2026 Confluent, Inc.
@REM
@REM Run only the performance test suite (tests tagged @Tag("performance")).
@REM These are excluded from the regular CI build because they take a long time
@REM and need substantial hardware. Used by the self-hosted Windows runner.
@REM
@REM Usage: bin\performance-test.cmd [extra-maven-args...]

@echo off
setlocal

call mvnw.cmd --batch-mode ^
-Pci ^
clean verify ^
-Dincluded.groups=performance ^
-Dexcluded.groups= ^
-Dlicense.skip ^
%*
21 changes: 21 additions & 0 deletions bin/performance-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
#
# Copyright (C) 2020-2026 Confluent, Inc.
#

# Run only the performance test suite (tests tagged @Tag("performance")).
# These are excluded from the regular CI build because they take a long time
# and need substantial hardware. The self-hosted runner workflow
# (.github/workflows/performance.yml) calls this script.
#
# Usage: bin/performance-test.sh [extra-maven-args...]

set -euo pipefail

./mvnw --batch-mode \
-Pci \
clean verify \
-Dincluded.groups=performance \
-Dexcluded.groups= \
-Dlicense.skip \
"$@"
11 changes: 11 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
coverage:
status:
project:
default:
# Fail if overall coverage drops from the base branch
target: auto
threshold: 1%
patch:
default:
# Don't enforce a minimum on new code — just track it
informational: true
Loading
Loading