rholshausen
07/03/2026, 1:35 AMrholshausen
07/03/2026, 1:38 AMJoshua Ellis
07/03/2026, 1:55 AMlibpython to be present, so should run most places, but not everywhere
Python has a stable ABI, which we presumably can leverage. This means that as long as the user has a relatively recent version of Python on their system, the plugin should run just fine.rholshausen
07/03/2026, 1:57 AMJoshua Ellis
07/03/2026, 1:57 AMrholshausen
07/03/2026, 1:59 AMrholshausen
07/03/2026, 1:59 AMJoshua Ellis
07/03/2026, 2:01 AMJoshua Ellis
07/03/2026, 2:02 AMJoshua Ellis
07/03/2026, 2:03 AMPython.dll and place it in the plugins directory so that the Pact can link against it?rholshausen
07/03/2026, 2:04 AMrholshausen
07/03/2026, 2:05 AMrholshausen
07/03/2026, 2:10 AMrholshausen
07/03/2026, 2:11 AMrholshausen
07/03/2026, 2:12 AMJoshua Ellis
07/03/2026, 2:16 AMrholshausen
07/03/2026, 2:17 AMrholshausen
07/03/2026, 4:15 AMAli Ustek
08/21/2026, 8:18 PMAli Ustek
08/21/2026, 8:18 PMpact-avro-plugin in Scala (JVM)
Choosing Scala for the Avro plugin was a pragmatic architectural decision driven by three main realities:
1. Definitive Avro Semantics (org.apache.avro)
The reference Apache Avro Java implementation has always been the golden standard. Complex schema evolution, datum readers/writers, logical types (e.g., timestamps, decimals), and Confluent Schema Registry wire formats are fully supported and battle-tested on the JVM. Trying to replicate exact Avro evolution edge cases in non-JVM ports often leads to subtle deserialization discrepancies.
2. Expressive Functional Modeling
Pact content matching requires parsing ASTs, comparing payload diffs, extracting matching rules, and recursively walking schema hierarchies. Scala’s pattern matching, case classes, and type-level safety made modeling complex Avro schema ASTs and diff trees straightforward and robust.
3. Akka/Pekko gRPC & JVM Tooling
Integrating standard gRPC code generation (ScalaPB / fs2-grpc / Pekko gRPC) allowed strong type safety across the protobuf contracts required by the Pact plugin driver.
The Friction Points Encountered on the JVM
While Scala/JVM solved the Avro schema compatibility problem effortlessly, it introduced specific distribution and lifecycle headaches:
• Startup & Process Spawning Overhead: Pact plugins are spawned as child processes on demand. A fat JAR requires a JVM startup cycle (plus requiring users to have Java 17+ pre-installed in their test runner environments).
• Cross-Language Consumer Friction: A non-JVM developer (e.g., Python, Go, TypeScript) using the Avro plugin shouldn't ideally need a full JRE installed just to run their local contract tests.
• Packaging Complexity: Solving the distribution problem via GraalVM Native Image to emit static binaries requires configuring reflection configs for Avro's runtime reflection and gRPC netty transports.
The Verdict: Stick with Scala or Rewrite in Rust?
DimensionKeep / Evolve in Scala (JVM)Port to RustAvro Correctness10/10 — Native Apache Avro engine; zero risk with custom logical types or Schema Registry wire formats.7/10 — apache-avro crate is solid, but lacks complete feature parity with Java Avro edge cases.*Plugin Distribution*Requires Java 17+ runtime on user machines or GraalVM Native Image build complexity.10/10 — Pure static binary per OS/architecture; zero runtime prereqs for users.*Pact Alignment*Second-party JVM driver integration.10/10 — Direct alignment with Pact core Rust crates (pact_models, pact_plugin_driver).*Maintenance Cost*Low if you already maintain the codebase and understand the Scala ecosystem.High upfront rewrite effort to replicate the full matching engine logic.
Architectural Conclusion
• If maintaining feature depth and enterprise Avro parity is priority #1:
Stay with Scala. The reliability of the official Java Avro library outweighs the inconvenience of a Java prerequisite, particularly since the vast majority of enterprise teams relying heavily on Kafka + Avro already run JVM tooling in their build pipelines.
• If frictionless, universal zero-prerequisite distribution across all Pact ecosystems is the goal:
Port the core matching logic to Rust, using tonic for gRPC and apache-avro, wrapping it as a multi-arch static binary release.rholshausen
08/23/2026, 11:35 PMrholshausen
08/23/2026, 11:37 PM