From c18d76eaa841571bbe92977b70a95c7fe7255fb2 Mon Sep 17 00:00:00 2001 From: scottf Date: Tue, 24 Feb 2026 17:14:21 -0500 Subject: [PATCH 1/3] PCG-CLI build and readme --- .github/workflows/pcgcli-main.yml | 4 +- .github/workflows/pcgcli-pr.yml | 20 ++++++-- pcgroups-cli/README.md | 82 +++++++++++++++++++++++++++++++ pcgroups-cli/build.gradle | 62 +++++++++++------------ pcgroups/README.md | 11 +++++ pcgroups/build.gradle | 2 +- 6 files changed, 141 insertions(+), 40 deletions(-) create mode 100644 pcgroups-cli/README.md diff --git a/.github/workflows/pcgcli-main.yml b/.github/workflows/pcgcli-main.yml index 003b2e5..3c2c42d 100644 --- a/.github/workflows/pcgcli-main.yml +++ b/.github/workflows/pcgcli-main.yml @@ -26,7 +26,7 @@ jobs: chmod +x gradlew && ./gradlew clean test uberJar - name: Build with Maven run: mvn clean package - - name: Validate Gradle Uber was created + - name: Validate Gradle Executable Jar was created run: | FILE_PATH="build/libs/cg.jar" if [ -f "$FILE_PATH" ]; then @@ -35,7 +35,7 @@ jobs: echo "Validation failed: $FILE_PATH was not found." exit 1 # Fails the workflow step fi - - name: Validate Maven Uber was created + - name: Validate Maven Executable Jar was created run: | FILE_PATH="target/cg.jar" if [ -f "$FILE_PATH" ]; then diff --git a/.github/workflows/pcgcli-pr.yml b/.github/workflows/pcgcli-pr.yml index b91da6b..250888d 100644 --- a/.github/workflows/pcgcli-pr.yml +++ b/.github/workflows/pcgcli-pr.yml @@ -22,10 +22,10 @@ jobs: uses: actions/checkout@v4 - name: Build with Gradle run: | - chmod +x gradlew && ./gradlew clean test uberJar + chmod +x gradlew && ./gradlew clean package - name: Build with Maven run: mvn clean package - - name: Validate Gradle Uber was created + - name: Validate artifacts were created run: | FILE_PATH="build/libs/cg.jar" if [ -f "$FILE_PATH" ]; then @@ -34,8 +34,20 @@ jobs: echo "Validation failed: $FILE_PATH was not found." exit 1 # Fails the workflow step fi - - name: Validate Maven Uber was created - run: | + FILE_PATH="build/cg.zip" + if [ -f "$FILE_PATH" ]; then + echo "Validation successful: $FILE_PATH was created." + else + echo "Validation failed: $FILE_PATH was not found." + exit 1 # Fails the workflow step + fi + FILE_PATH="build/libs/cg.tar" + if [ -f "$FILE_PATH" ]; then + echo "Validation successful: $FILE_PATH was created." + else + echo "Validation failed: $FILE_PATH was not found." + exit 1 # Fails the workflow step + fi FILE_PATH="target/cg.jar" if [ -f "$FILE_PATH" ]; then echo "Validation successful: $FILE_PATH was created." diff --git a/pcgroups-cli/README.md b/pcgroups-cli/README.md new file mode 100644 index 0000000..52014c5 --- /dev/null +++ b/pcgroups-cli/README.md @@ -0,0 +1,82 @@ +Orbit + +# Partitioned Consumer Groups CLI + +The Partitioned Consumer Groups CLI is a command line tool. In the usage, + +`cg` stands for `java -jar /cg.jar` + +``` +Usage: cg [options] + +Commands: + static Static consumer groups mode + elastic Elastic consumer groups mode + +Use 'cg --help' for more information about a command. +``` + +``` +Usage: cg static [COMMAND] +Static consumer groups mode +Commands: + ls, list List static consumer groups for a stream + info Get static consumer group info + create Create a static partitioned consumer group + delete, rm Delete a static partitioned consumer group + member-info, memberinfo, minfo Get static consumer group member info + step-down, stepdown, sd Initiate a step down for a member + consume, join Join a static partitioned consumer group + prompt Interactive prompt mode +``` + +``` +Usage: cg elastic [COMMAND] +Elastic consumer groups mode +Commands: + ls, list List elastic consumer groups for a stream + info Get elastic consumer group info + create Create an elastic partitioned consumer + group + delete, rm Delete an elastic partitioned consumer + group + add Add members to an elastic consumer group + drop Drop members from an elastic consumer group + create-mapping, cm, createmapping Create member mappings for an elastic + consumer group + delete-mapping, dm, deletemapping Delete member mappings for an elastic + consumer group + member-info, memberinfo, minfo Get elastic consumer group member info + step-down, stepdown, sd Initiate a step down for a member + consume, join Join an elastic partitioned consumer group + prompt Interactive prompt mode +``` + +## Building from Source +The project contains both a Maven pom.xml file and a Gradle project, +and both are configured to build an executable Java jar named `cg.jar` + +### Maven +``` +mvn clean package +``` + +will build the `cg.jar` in the `target` folder + +### Gradle +``` +gradle clean package +``` +will build the `cg.jar` in the `build` folder + +## Running + + +``` +java -jar target/cg.jar ... +java -jar build/cg.jar ... +``` + +--- +Copyright (c) 2025 Synadia Communications Inc. All Rights Reserved. +See [LICENSE](LICENSE) and [NOTICE](NOTICE) file for details. diff --git a/pcgroups-cli/build.gradle b/pcgroups-cli/build.gradle index 91d173f..49e6271 100644 --- a/pcgroups-cli/build.gradle +++ b/pcgroups-cli/build.gradle @@ -1,17 +1,10 @@ plugins { id("java") - id("java-library") - id("maven-publish") - id("jacoco") - id("biz.aQute.bnd.builder") version "7.1.0" - id("org.gradle.test-retry") version "1.6.4" - id("io.github.gradle-nexus.publish-plugin") version "2.0.0" - id("signing") + id 'com.github.johnrengelman.shadow' version '8.1.1' // Apply the shadow plugin } -group = 'io.synadia' version = "0.1.0" -def originalUber = 'pcg-cli-' + version + '-uber.jar' +def originalShadow = 'pcg-cli-' + version + '-all.jar' java { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -27,7 +20,7 @@ repositories { dependencies { implementation 'io.nats:jnats:2.25.1' implementation 'org.jspecify:jspecify:1.0.0' - implementation 'io.synadia:pcgroups:0.1.0-SNAPSHOT' + implementation 'io.synadia:pcgroups:0.1.0' implementation 'info.picocli:picocli:4.7.5' testImplementation 'io.nats:jnats-server-runner:3.1.0' @@ -35,36 +28,39 @@ dependencies { testImplementation 'org.junit.platform:junit-platform-launcher:1.14.3' } -tasks.register('copyToLib', Copy) { - into "build/libs" - from configurations.runtimeClasspath +shadowJar { + manifest { + attributes 'Main-Class': 'io.synadia.pcg.cli.CgCommand' + } } -tasks.register('packageUberJar', Jar) { - archiveClassifier = 'uber' +tasks.register('makecg', Copy) { + dependsOn shadowJar - from sourceSets.main.output + // we want the file to be called cg.jar + from ('build/libs') + include originalShadow + destinationDir file('build/') + rename originalShadow, "cg.jar" +} - dependsOn configurations.runtimeClasspath - from { - configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) } - } +tasks.register('createZip', Zip) { + dependsOn makecg - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - dependsOn copyToLib + archiveFileName = "cg.zip" + destinationDirectory = file('build/') + from (files('build/cg.jar')) } -tasks.register('uberJar', Copy) { - dependsOn packageUberJar +tasks.register('createTar', Tar) { + dependsOn makecg - // we want the file to be called cg.jar - from ('build/libs') - include originalUber - destinationDir file('build/libs/') - rename originalUber, "cg.jar" + archiveFileName = "cg.tar" + destinationDirectory = file('build/') + from (files('build/cg.jar')) +} - // this task actually does a copy, so this part removes the original - doLast { - delete('build/libs/' + originalUber) - } +tasks.register('package') { + dependsOn createZip + dependsOn createTar } diff --git a/pcgroups/README.md b/pcgroups/README.md index 331021d..e59ff56 100644 --- a/pcgroups/README.md +++ b/pcgroups/README.md @@ -2,9 +2,17 @@ # Partitioned Consumer Groups +![Artifact](https://img.shields.io/badge/Artifact-io.synadia:pcgroups-197556?labelColor=grey&style=flat) +![0.1.0](https://img.shields.io/badge/Current_Release-0.1.0-27AAE0) +![0.1.1](https://img.shields.io/badge/Current_Snapshot-0.1.1--SNAPSHOT-27AAE0) +[![Dependencies Help](https://img.shields.io/badge/Dependencies%20Help-27AAE0)](https://github.com/synadia-io/orbit.java?tab=readme-ov-file#dependencies) +[![javadoc](https://javadoc.io/badge2/io.synadia/pcgroups/javadoc.svg)](https://javadoc.io/doc/io.synadia/pcgroups) +[![Maven Central](https://img.shields.io/maven-central/v/io.synadia/pcgroups)](https://img.shields.io/maven-central/v/io.synadia/pcgroups) + Initial implementation of a client-side partitioned consumer group feature for NATS streams leveraging some of the new features introduced in `nats-server` version 2.11. Note that post 2.11 versions of `nats-server` may include new features related to the consumer group use case that could render this client-side library unneeded (or make much smaller) + # Overview This library enables the parallelization through partitioning of the consumption of messages from a stream while ensuring a strict order of not just delivery but also successful consumption of the messages using all or parts of the message's subject as a partitioning key. @@ -54,6 +62,9 @@ Included is a small command line interface tool, named `cg` and located in the ` This `cg` CLI tool can be used by passing it commands and arguments directly, or with an interactive prompt using the `prompt` command (e.g. `cg static prompt`). +For more details on the CLI visit the [Partitioned Consumer Groups CLI Project](https://github.com/synadia-io/orbit.java/tree/main/pcgroups-cli) + + ## Demo walkthrough ### Static diff --git a/pcgroups/build.gradle b/pcgroups/build.gradle index 75f3332..225e274 100644 --- a/pcgroups/build.gradle +++ b/pcgroups/build.gradle @@ -11,7 +11,7 @@ plugins { id("signing") } -def jarVersion = "0.1.0" +def jarVersion = "0.1.1" group = 'io.synadia' def isRelease = System.getenv("BUILD_EVENT") == "release" From 001340a71763d3ac7077dec5331d98b4e599e184 Mon Sep 17 00:00:00 2001 From: scottf Date: Tue, 24 Feb 2026 17:16:27 -0500 Subject: [PATCH 2/3] PCG-CLI build and readme --- .github/workflows/pcgcli-main.yml | 20 ++++++++++++++++---- .github/workflows/pcgcli-pr.yml | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pcgcli-main.yml b/.github/workflows/pcgcli-main.yml index 3c2c42d..2e1e681 100644 --- a/.github/workflows/pcgcli-main.yml +++ b/.github/workflows/pcgcli-main.yml @@ -26,17 +26,29 @@ jobs: chmod +x gradlew && ./gradlew clean test uberJar - name: Build with Maven run: mvn clean package - - name: Validate Gradle Executable Jar was created + - name: Validate artifacts were created run: | - FILE_PATH="build/libs/cg.jar" + FILE_PATH="build/cg.jar" + if [ -f "$FILE_PATH" ]; then + echo "Validation successful: $FILE_PATH was created." + else + echo "Validation failed: $FILE_PATH was not found." + exit 1 # Fails the workflow step + fi + FILE_PATH="build/cg.zip" + if [ -f "$FILE_PATH" ]; then + echo "Validation successful: $FILE_PATH was created." + else + echo "Validation failed: $FILE_PATH was not found." + exit 1 # Fails the workflow step + fi + FILE_PATH="build/libs/cg.tar" if [ -f "$FILE_PATH" ]; then echo "Validation successful: $FILE_PATH was created." else echo "Validation failed: $FILE_PATH was not found." exit 1 # Fails the workflow step fi - - name: Validate Maven Executable Jar was created - run: | FILE_PATH="target/cg.jar" if [ -f "$FILE_PATH" ]; then echo "Validation successful: $FILE_PATH was created." diff --git a/.github/workflows/pcgcli-pr.yml b/.github/workflows/pcgcli-pr.yml index 250888d..43b15c3 100644 --- a/.github/workflows/pcgcli-pr.yml +++ b/.github/workflows/pcgcli-pr.yml @@ -27,7 +27,7 @@ jobs: run: mvn clean package - name: Validate artifacts were created run: | - FILE_PATH="build/libs/cg.jar" + FILE_PATH="build/cg.jar" if [ -f "$FILE_PATH" ]; then echo "Validation successful: $FILE_PATH was created." else From f4992da19b8dae046217c8f5f4cf4492fcc520a6 Mon Sep 17 00:00:00 2001 From: scottf Date: Tue, 24 Feb 2026 17:29:02 -0500 Subject: [PATCH 3/3] PCG-CLI build and readme --- .github/workflows/pcgcli-main.yml | 58 ------------------- .../workflows/{pcgcli-pr.yml => pcgcli.yml} | 10 ++-- pcgroups-cli/build.gradle | 8 +-- 3 files changed, 10 insertions(+), 66 deletions(-) delete mode 100644 .github/workflows/pcgcli-main.yml rename .github/workflows/{pcgcli-pr.yml => pcgcli.yml} (90%) diff --git a/.github/workflows/pcgcli-main.yml b/.github/workflows/pcgcli-main.yml deleted file mode 100644 index 2e1e681..0000000 --- a/.github/workflows/pcgcli-main.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Partitioned Consumer Groups CLI Main Snapshot - -on: - push: - branches: - - main - paths: - - 'pcgroups-cli/**' - -jobs: - build: - runs-on: ubuntu-latest - defaults: - run: - working-directory: ./pcgroups-cli - steps: - - name: Set up JDK - uses: actions/setup-java@v5 - with: - java-version: '21' - distribution: 'temurin' - - name: Check out code - uses: actions/checkout@v4 - - name: Build with Gradle - run: | - chmod +x gradlew && ./gradlew clean test uberJar - - name: Build with Maven - run: mvn clean package - - name: Validate artifacts were created - run: | - FILE_PATH="build/cg.jar" - if [ -f "$FILE_PATH" ]; then - echo "Validation successful: $FILE_PATH was created." - else - echo "Validation failed: $FILE_PATH was not found." - exit 1 # Fails the workflow step - fi - FILE_PATH="build/cg.zip" - if [ -f "$FILE_PATH" ]; then - echo "Validation successful: $FILE_PATH was created." - else - echo "Validation failed: $FILE_PATH was not found." - exit 1 # Fails the workflow step - fi - FILE_PATH="build/libs/cg.tar" - if [ -f "$FILE_PATH" ]; then - echo "Validation successful: $FILE_PATH was created." - else - echo "Validation failed: $FILE_PATH was not found." - exit 1 # Fails the workflow step - fi - FILE_PATH="target/cg.jar" - if [ -f "$FILE_PATH" ]; then - echo "Validation successful: $FILE_PATH was created." - else - echo "Validation failed: $FILE_PATH was not found." - exit 1 # Fails the workflow step - fi diff --git a/.github/workflows/pcgcli-pr.yml b/.github/workflows/pcgcli.yml similarity index 90% rename from .github/workflows/pcgcli-pr.yml rename to .github/workflows/pcgcli.yml index 43b15c3..569c145 100644 --- a/.github/workflows/pcgcli-pr.yml +++ b/.github/workflows/pcgcli.yml @@ -1,6 +1,9 @@ -name: Partitioned Consumer Groups CLI Pull Request +name: Partitioned Consumer Groups CLI Build on: + push: + branches: + - main pull_request: types: [opened, synchronize, reopened] paths: @@ -21,8 +24,7 @@ jobs: - name: Check out code uses: actions/checkout@v4 - name: Build with Gradle - run: | - chmod +x gradlew && ./gradlew clean package + run: chmod +x gradlew && ./gradlew clean dist - name: Build with Maven run: mvn clean package - name: Validate artifacts were created @@ -41,7 +43,7 @@ jobs: echo "Validation failed: $FILE_PATH was not found." exit 1 # Fails the workflow step fi - FILE_PATH="build/libs/cg.tar" + FILE_PATH="build/cg.tar" if [ -f "$FILE_PATH" ]; then echo "Validation successful: $FILE_PATH was created." else diff --git a/pcgroups-cli/build.gradle b/pcgroups-cli/build.gradle index 49e6271..094794d 100644 --- a/pcgroups-cli/build.gradle +++ b/pcgroups-cli/build.gradle @@ -34,7 +34,7 @@ shadowJar { } } -tasks.register('makecg', Copy) { +tasks.register('package', Copy) { dependsOn shadowJar // we want the file to be called cg.jar @@ -45,7 +45,7 @@ tasks.register('makecg', Copy) { } tasks.register('createZip', Zip) { - dependsOn makecg + dependsOn 'package' archiveFileName = "cg.zip" destinationDirectory = file('build/') @@ -53,14 +53,14 @@ tasks.register('createZip', Zip) { } tasks.register('createTar', Tar) { - dependsOn makecg + dependsOn 'package' archiveFileName = "cg.tar" destinationDirectory = file('build/') from (files('build/cg.jar')) } -tasks.register('package') { +tasks.register('dist') { dependsOn createZip dependsOn createTar }