createCircuitsEngineClient
createCircuitsEngineClient(
options):object
Defined in: packages/server/src/circuits/engine-client.ts:38
The control plane’s client for the Circuits engine.
Only the shape LIFECYCLE goes through here. Reads never do: they terminate on durable-streams, which is the whole point of the native topology — the engine is asked once, at subscribe time, for a stream to follow, and is then out of the read path entirely.
Parameters
Section titled “Parameters”options
Section titled “options”Returns
Section titled “Returns”createShape()
Section titled “createShape()”createShape(
request):Promise<CircuitsShapeHandle>
Register a shape and get the stream to follow — and renew that registration.
There is deliberately no renewShape: a renewal IS this call, repeated with the same
request.subscription on the same definition (fork ADR-0008). The engine answers the same
handle, counts nothing extra, and moves the lease forward. That is also why a create whose
response was lost can simply be sent again, and why the control plane’s token re-mint can renew
every live claim without a second route.
Two outcomes a caller must distinguish:
- 409 (CircuitsEngineError.status) — the id names a DIFFERENT shape already. One name, one shape; nothing was taken, and a retry will not change it.
- a different handle — the claim had lapsed or the shape was evicted, so this call re-subscribed rather than renewed. The stream the old grant named is not this one (ADR-0007).
The engine shares by definition: two identical bodies collapse onto one maintained stream and return the same handle. Nothing here has to check for that or cache against it — which is exactly why the shared tier’s predicate must be GENERATED. Two subscribers in one scope produce identical bodies only because neither’s identity reached the predicate; they are still two distinct subscriptions, because each names its own claim.
The answer is VALIDATED, not cast, for the same reason replicationState validates the barrier: an engine that acknowledges a create without saying which subscription it recorded or how long that subscription lives cannot be renewed or released by id at all, and defaulting either field would invent a lease this control plane was never promised.
Parameters
Section titled “Parameters”request
Section titled “request”Returns
Section titled “Returns”Promise<CircuitsShapeHandle>
releaseShape()
Section titled “releaseShape()”releaseShape(
shapeId,subscription):Promise<void>
Release ONE named subscription’s claim on a shape (DELETE /shapes/{id}?subscription=…).
Idempotent, and that is the whole point of naming the claim: releasing one that is already
gone is a no-op 200 rather than a decrement that steals another subscriber’s. A caller whose
response was lost may simply send it again.
There is no anonymous form here. The engine still accepts a bare DELETE /shapes/{id} as a
legacy refcount decrement, but it carries no claim identity and is not retry-safe, so this
client never issues one.
The shape itself survives its other subscribers and then follows the engine’s retention lifecycle (idle → dormant → evicted); this is a release, not a delete.
Parameters
Section titled “Parameters”shapeId
Section titled “shapeId”string
subscription
Section titled “subscription”string
Returns
Section titled “Returns”Promise<void>
replicationState()
Section titled “replicationState()”replicationState():
Promise<CircuitsReplicationState>
The engine’s convergence barrier (ADR-0056): where replication is, how many computed-but-undelivered subquery flips remain, and how many flip batches the engine gave up on.
The engine answers a sync field beside these and it is deliberately NOT read: it is the
__el_sync sentinel watermark — an i64 the engine’s conformance harness bumps and waits on as
a global quiescence fence — which no pgxsinkit database ever writes, so it is 0 everywhere and
says nothing about convergence.
pendingFlips > 0 means a revocation has been computed and not yet written to any stream,
which no wire-format watermark can see. That is the term the Electric wire could not express
at all, and the reason the barrier is read out of band rather than inferred from a position.
flipFailures > 0 means a batch was abandoned after exhausting its propagation retries:
those membership effects are gone rather than late. The engine keeps the abandoned batch’s
pendingFlips count held — so the waiting terms never falsely read converged — and latches
itself degraded: /ready answers 503, so do its membership-bearing routes, and a reaper
deletes every subquery shape stream. Recovery is an operator restart.
The answer is VALIDATED, not cast. An engine that does not report both counters cannot answer the question this barrier asks, and defaulting a missing term to zero would manufacture a converged reading out of an engine that never claimed one.
Returns
Section titled “Returns”Promise<CircuitsReplicationState>