Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
83 changes: 62 additions & 21 deletions .github/workflows/clients.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
# itself, absence means the setup step did not do what it claimed, and a green skip would be
# docs/solutions/workflow-issues/a-check-that-reports-success-without-having-run.md again.
#
# WHAT THIS WORKFLOW DELIBERATELY DOES NOT DO YET: no protoc provisioning, no conformance suite, no
# per-language static analysis, no per-language dependency audit. All four exist on
# astubbs/parallel-consumer#293 and all four are about content this rung does not ship. They arrive
# with the rungs that add what they check.
# WHAT THIS WORKFLOW DELIBERATELY DOES NOT DO YET: no conformance lane, no per-language static
# analysis, no per-language dependency audit. All three exist on astubbs/parallel-consumer#293. The
# conformance lane has nothing to run - driving a client's runner needs an engine behind the sidecar
# and there is none - and the analysis and audit lanes are their own extraction, tracked in
# docs/inflight/static-polyglot-client-analysers.md. Each module's own build already gates on what
# its language treats as a compile error, which for .NET, Rust, Swift and Scala is most of it.
#
# Caching: the same discipline as maven.yml - explicit restore with a rotating save key, never a
# setup action's built-in `cache:`, whose immutable keys can freeze an incomplete cache
Expand Down Expand Up @@ -93,22 +95,27 @@ jobs:
module: parallel-consumer-proxy-client-dotnet
runner: ubuntu-latest
toolchain: '9.0.x'
# The runner image's own compilers. There is no version to pin and nothing to install:
# the module compiles one translation unit with `c++`, which every ubuntu image has.
# C++ AND SWIFT BUILD IN CONTAINERS, AND BOTH ROWS THEREFORE PIN AN IMAGE RATHER THAN A
# TOOLCHAIN. Each module carries a multi-stage Dockerfile whose FROM line is the pin, and
# bin/build-client.sh drives BuildKit and exports the artifact stage; the image also runs
# the module's own tests and its static analysis, so a red one fails the row. Neither
# language can be served from the host: gRPC and protobuf reach C++ as system DEV
# PACKAGES rather than as a versioned toolchain, and Swift.org publishes no toolchain in
# the ubuntu images. `toolchain` is therefore empty and `docker` is what the probe below
# checks.
#
# SWIFT MOVED OFF macos-latest WITH THE REAL CLIENT. While the module printed one line it
# needed a compiler and nothing else, and the macOS image's bundled Swift was the cheapest
# answer; the real client needs grpc-swift, swift-protobuf and two protoc plugins built
# from source, which is what the image already assembles and caches. A macOS row would
# have to reproduce all of it outside a container.
- language: cpp
module: parallel-consumer-proxy-client-cpp
runner: ubuntu-latest
toolchain: ''
# SWIFT RUNS ON macOS, AND THAT IS THE CHEAPEST HONEST OPTION. Swift.org publishes no
# toolchain in the ubuntu images, so a Linux row needs either a third-party setup action
# or a container - and astubbs/parallel-consumer#293 takes the container route precisely
# because its C++ and Swift clients need gRPC and protobuf development packages. This
# module needs a compiler and nothing else, so the macOS image's bundled Swift answers
# the whole question with no extra moving part. Revisit when the real Swift client
# arrives and brings its own dependency needs.
- language: swift
module: parallel-consumer-proxy-client-swift
runner: macos-latest
runner: ubuntu-latest
toolchain: ''

steps:
Expand Down Expand Up @@ -152,11 +159,44 @@ jobs:
with:
ruby-version: ${{ matrix.toolchain }}
bundler-cache: false
# `--component clippy` is NOT optional decoration on a minimal profile: this module's build
# command IS `cargo clippy` (the Rust wave's decision - its pom carries the reasoning), and a
# minimal toolchain ships rustc and cargo and nothing else, so the row failed with
# "'cargo-clippy' is not installed for the toolchain" before the crate was ever compiled.
- name: Set up Rust toolchain (rustup is preinstalled on the runner image)
if: matrix.language == 'rust'
run: |
rustup toolchain install ${{ matrix.toolchain }} --profile minimal
rustup toolchain install ${{ matrix.toolchain }} --profile minimal --component clippy
rustup default ${{ matrix.toolchain }}
cargo clippy --version

# protoc, for the ONE row whose build runs it on the runner. That is a smaller set than
# "generates from the schema": Go, Ruby and TypeScript commit their stubs, .NET's Grpc.Tools
# package ships its own protoc, and C++ and Swift generate inside their images. Rust's
# build.rs runs prost/tonic codegen on every `cargo build`, so without this the row fails in
# the build, the test and the analysis step identically.
#
# LIBPROTOBUF-DEV IS NOT OPTIONAL DESPITE NOTHING HERE LINKING C++, and leaving it out is
# exactly how this row failed once: `protobuf-compiler` ships the binary and NOT the
# well-known types, so protoc ran and then could not resolve the schema's own imports -
# `google/protobuf/duration.proto: File not found`, which reads as a broken .proto rather
# than a half-installed toolchain. The Swift module's Dockerfile carries the same pairing and
# the same sentence; it was already written down here and this row did not read it.
#
# Where the types land is what the crate's build script looks for: it takes `../include`
# relative to the resolved protoc, which for /usr/bin/protoc is /usr/include - the directory
# this package fills. apt rather than a setup action for that reason: the binary and the
# types come from one distribution and land where each other expects.
- name: Install protoc (rust generates from the frozen schema on every build)
if: matrix.language == 'rust'
run: |
sudo apt-get update
sudo apt-get install --yes --no-install-recommends protobuf-compiler libprotobuf-dev
protoc --version
# Prove the types are there before the crate needs them, so a half-installed toolchain
# fails HERE naming the package rather than three minutes later naming the schema.
test -f /usr/include/google/protobuf/duration.proto \
|| { echo "::error::libprotobuf-dev did not provide the well-known types"; exit 1; }

# Prove the toolchain is where the strict guard will look for it. A setup action that
# silently no-ops leaves a row whose only symptom is a red build several steps later blaming
Expand All @@ -170,16 +210,17 @@ jobs:
rust) cargo --version ;;
ruby) ruby --version ;;
dotnet) dotnet --version ;;
cpp) c++ --version ;;
swift) swift --version ;;
# Both container rows: what has to be present is Docker, not a language toolchain.
cpp | swift) docker --version && docker buildx version ;;
*) echo "::error::no toolchain probe for ${{ matrix.language }} - add one when you add the row"; exit 1 ;;
esac

# -Dpc.foreignClients puts this module in the reactor at all; the compile phase runs its
# native build and the test phase runs its program and asserts the fixture line. --fail-at-end
# for the reason the reactor lanes in bin/ci-*.sh carry it: one run, as much breakage as it
# can find.
- name: Build and run the hello fixture (${{ matrix.module }})
# native build and the test phase runs its own suite - which for eight of the ten includes a
# handshake against a real sidecar process this reactor has just built, so `-am` is what makes
# parallel-consumer-proxy exist for it to spawn. --fail-at-end for the reason the reactor lanes
# in bin/ci-*.sh carry it: one run, as much breakage as it can find.
- name: Build and test (${{ matrix.module }})
run: >-
./mvnw --batch-mode -Pci --fail-at-end package
-pl :${{ matrix.module }} -am -Dpc.foreignClients
15 changes: 11 additions & 4 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,18 @@ jobs:
# from the plugin's own zinc dependency and no pom property carries it, so a `dependency:get`
# would need a literal that rots silently the next time the plugin is bumped - and warming
# the wrong coordinate is indistinguishable from a cache hit until it fails four jobs
# downstream. `-am` keeps this to the Scala module's own reactor chain, which is the root
# pom, the clients aggregator and the module itself: it declares no Parallel Consumer
# dependency, so nothing else is built here. (astubbs#242)
# downstream. (astubbs#242)
#
# `test-compile`, NOT `compile`, and the difference is load-bearing rather than a wider net.
# The Scala module now depends on the gRPC transport, which reaches the protocol module, which
# TEST-depends on parallel-consumer-core's test-jar. Maven resolves an inter-module test-jar
# from the reactor only once the producing module has reached test-compile; stopped at
# `compile` it falls back to the repository, and on a runner with an empty ~/.m2 that is
# `Could not find artifact ...core:jar:tests` - which fails this job, and with it the cache
# save every other lane restores from. Nothing about this is local: a developer's ~/.m2 holds
# the artifact from any earlier build, so the failure only exists on a cold machine.
- name: Warm scala-maven-plugin's compiler and zinc bridge
run: ./mvnw --batch-mode -Pci -pl :parallel-consumer-proxy-client-scala -am compile
run: ./mvnw --batch-mode -Pci -pl :parallel-consumer-proxy-client-scala -am test-compile
- name: Save Maven cache (rotating key)
if: success()
uses: actions/cache/save@v4
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ bin/performance-test.sh # performance tests (substantial hardware)
| `parallel-consumer-mutiny` | SmallRye Mutiny integration (Quarkus) |
| `parallel-consumer-proxy-protocol` | The **frozen** v1 wire contract for the language proxy: `proxy.proto`, its specification and client-authoring guide, and the tests and `buf` gates that keep it frozen. The wire may only gain - `bin/check-proto-breaking.sh` enforces it, and that module's `README.md` owns the detail |
| `parallel-consumer-proxy` | The sidecar. **Packaging and process boundary only today** - an executable that binds loopback, admits one connection under the transport's rules, and dies with its parent; it hosts no engine, so a session is answered `UNIMPLEMENTED`. That module's `README.md` owns the detail, including what is not there yet |
| `parallel-consumer-proxy-clients` | Eleven language client modules, plus the **shared conformance suite** - one definition of correct for every client, with Parallel Consumer itself as the control arm; `parallel-consumer-proxy-conformance/README.md` owns it, including which cells are deferred and why. **Java is a real client** - a shared surface with an in-process and a gRPC transport under it, gated by its own SpotBugs lane; the other ten are still build scaffolding (toolchain, compile, run, one fixture line). The eight non-JVM ones are outside the reactor unless `-Dpc.foreignClients` is passed, and an absent toolchain is reported and skipped rather than failing. That directory's `README.md` owns the detail |
| `parallel-consumer-proxy-clients` | Eleven language client libraries, plus the **shared conformance suite** - one definition of correct for every client, with Parallel Consumer itself as the control arm; `parallel-consumer-proxy-conformance/README.md` owns it, including which cells are deferred and why. All eleven implement **negotiated dispatch only**: each declares the `dispatch` capability and no other, so an engine that supports more will not use it with these clients. What any of them is evidenced to do stops at the handshake, because the sidecar hosts no engine - the per-client rows in `docs/data/testing-evidence.yaml` say so one by one. The eight non-JVM modules are outside the reactor unless `-Dpc.foreignClients` is passed, and an absent toolchain is reported and skipped rather than failing (`bin/foreign-client-step.sh`); C++ and Swift build in their own containers through `bin/build-client.sh`. That directory's `README.md` owns the detail |
| `parallel-consumer-examples` | Example implementations for each module |

## Key Architecture Decisions
Expand Down
Loading
Loading