Use a Contract Registry
A contract normally comes from a file the job carries with it — but a file has no shared
place other jobs, CI pipelines, or platform tooling can look up, version, or govern
independently of any one job’s own deployment. registry://<id>@<version> lets
spark.invaract.contract name a contract stored in a contract registry — a small HTTP
service that stores versions of a contract, computes a compatibility diff against the
previous version on every new registration, and rejects a registration whose declared
version bump doesn’t match the actual scope of change unless explicitly overridden.
What you need running
Section titled “What you need running”A registry server, reachable over HTTP from wherever your job runs, implementing the
wire protocol (routes, request/response shapes,
status codes). Nothing else in this guide, or in spark-adapter’s resolution
mechanism, assumes a specific server implementation — registry-client only speaks
the documented HTTP protocol.
Register a contract
Section titled “Register a contract”-
Write an ordinary contract, the same as any other — see Write a Contract.
-
PUTit to the registry:Terminal window curl -X PUT http://localhost:7000/contracts/customer_orders/versions/1.0.0 \-H "Content-Type: application/yaml" \--data-binary @customer_orders.yamlA first-ever version returns
201with an empty compatibility report:{"changes":[]} -
Registering a later version reuses
contract’s ownContractCompatibilitydiff — the same logic Check Contract Compatibility describes — to reject a version bump that doesn’t match the actual scope of change (?expectedPrevious=1.0.0for the optimistic-concurrency check,?force=trueto override a rejected bump).
Point a job at it, purely via spark-submit --conf
Section titled “Point a job at it, purely via spark-submit --conf”No change to a job’s own source is needed — the same attachability guarantee every other
spark.invaract.* conf key in this documentation gives you:
spark-submit \ --class com.example.MyRealJob \ --master yarn \ --conf spark.sql.extensions=com.invaract.sparkadapter.InvaractSparkSessionExtension \ --conf spark.invaract.contract=registry://customer_orders@2.1.0 \ --conf spark.invaract.registryUrl=https://registry.corp.internal \ --jars invaract-spark-adapter-0.5.0.jar,invaract-registry-client-0.1.0.jar \ my-job.jarregistry://customer_orders@2.1.0 names an exact version; registry://customer_orders@latest
resolves to whatever the registry currently considers the latest registered version for
that id. Both parts are needed: a reference without a version, such as registry://customer_orders,
is refused when the job starts with
'registry://customer_orders' is not a valid contract reference: write it as 'registry://<id>@<version>' (the version may be 'latest').
Need a resolver --conf can’t express?
Section titled “Need a resolver --conf can’t express?”Call registry-client directly in code, the same “conf path required, code path is a
bonus” composition every other resolution mechanism in this documentation follows:
import com.invaract.registryclient.HttpContractRegistryClientimport com.invaract.sparkadapter.ContractEnforcementRule
val client = new HttpContractRegistryClient()client.configure("https://registry.corp.internal")val contract = client.getLatest("customer_orders")
val spark = SparkSession.builder() .withExtensions(_.injectCheckRule(ContractEnforcementRule.forContract(contract))) .getOrCreate()Trying it against the demo job
Section titled “Trying it against the demo job”./dev/registry-demoNeeds a local clone of the reference server implementation next to this repository (or
INVARACT_REGISTRY_DIR pointing at one elsewhere) — see the caution above on why that
repo isn’t publicly cloneable; this script is for anyone with access to it, or an
equivalent implementation of the documented wire protocol at that path. See the
Invaract Registry docs
for how to build and run one from a checkout you do have access to. The script
starts a real registry server, registers demo/contracts/invaract_output_registry.yaml
into it over real HTTP, then runs DemoJobHarness against
registry://invaract_demo_output_registry@1.0.0 — confirmed against a real run, not
just described. Its contractVerification section:
{ "status": "PASSED", "contract": "invaract_demo_output_registry@1.0.0", "contractPath": "registry://invaract_demo_output_registry@1.0.0", "violations": []}contractPath staying the literal registry://... string, rather than a resolved file
path, is what confirms the run went through registry resolution end to end.
What’s next
Section titled “What’s next”A persistent registry storage backend (the reference implementation is in-memory, not durable across restarts), real SSO/OIDC auth, and cross-contract policies or fingerprint-based drift control consuming the registry are all named, disclosed future work — see the wire protocol’s “Non-goals” section and the Invaract Registry docs’ Known Limitations page for the current state of each.