Sign in

    mooncdc

    PostgreSQL to ClickHouse CDC library and replicator with durable checkpoints

    postgresql
    cdc
    replication
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    3 days ago
    Downloads
    13

    #MoonCDC

    English is the authoritative version.

    A MoonBit PostgreSQL → ClickHouse CDC library and standalone replication tool. The library and CLI have equal support and share the run_pipeline core. Initial source acceptance covers PG17/18; see the release scope. The low-level subscription uses native pgoutput protocol v1, delivers complete committed transactions, and provides explicit acknowledgement, durable checkpoints and bounded reconnection.

    0.1.0: a native PostgreSQL → ClickHouse library and CLI. See testing for validation methods and historical evidence. Delivery is at least once; applications must handle replay.

    The fixed product inputs passed 4 Linux PG17/18 library cells and 8 CLI cells on 2026-10-20. The compiler window's 256-task budget is distinct from the database matrix: the diagnostic observed a kernel peak of 264 under a temporary 512 ceiling and 384 stop watermark, then restored 256. These are fixture budgets, not product requirements, permanent permission for 512 tasks, or evidence that a final release commit passed remote CI. See the version binding in testing.

    #Installation and usage

    First query the registry with moon view pangbit/mooncdc@0.1.0. When that version is available, install with moon add pangbit/mooncdc@0.1.0 and verify the resolved version. If unavailable, run the repository examples or follow releasing to validate an extracted source-package consumer. A local consumer pass does not establish registry publication.

    Set preferred_target = "native" in moon.mod and import the package in the consumer's moon.pkg. The examples use the default alias @mooncdc:

    ///|
    import {
    "pangbit/mooncdc",
    }

    ///|
    test "parse a PostgreSQL WAL position" {
    let position = @mooncdc.Lsn::parse("16/B374D848")
    assert_eq(position.to_string(), "16/B374D848")
    assert_true(position > @mooncdc.Lsn::parse("0/FFFFFFFF"))
    }

    A host embedding run_pipeline can observe worker activity and health. ready means running without a detected stall; it does not mean the initial copy is complete or WAL has caught up.

    ///|
    test "pipeline health before startup and during shutdown" {
    let control = @mooncdc.ApplyControl()
    assert_true(control.health().live)
    assert_false(control.health().ready)
    assert_eq(control.activities().length(), 0)
    control.stop()
    assert_eq(control.health().status, "stopping")
    }

    Wrap pipeline initialization and execution in with_health_server(control, () => { ... }) to enable HTTP probes. The default port is 9001, exposing /livez and /readyz; no listener starts unless called. The host must call control.stop() and await drain. See health contracts.

    run_pipeline copies all initial rows by default. Use table_sync_copy=SkipAllTables, IncludeTables([oid, ...]) or SkipTables([oid, ...]) to select initial table rows. Skipped tables still receive target initialization and schema setup, and still join later WAL. This is not a streaming filter. Restart does not refill already completed tables; see the pipeline contract.

    with_state_schema_store persists schema history in a file or PostgreSQL StateStore. Use separate namespaces for the pipeline's StateStore and schema store, and pass the same schemas to the destination and run_pipeline. See state stores.

    A typical consumer follows; complete runnable programs are in examples.

    let config = @mooncdc.ConnectionConfig::new(
    host="127.0.0.1", port=55418, user="cdc",
    password=password_from_environment, database="postgres",
    security=@mooncdc.LocalPlaintext,
    )
    @mooncdc.subscribe(
    config, slot="my_slot", publication="my_publication",
    start=@mooncdc.Resume, checkpoint_path="./state/checkpoint",
    sub => {
    for ;; {
    let tx = sub.next()
    persist_transaction_idempotently(tx) // 业务内容与 tx.id 一起持久化
    sub.ack(tx) // 之后才允许推进源端反馈
    }
    },
    )

    For the first run, use the explicit LSN returned when the replication slot is created: At(Lsn::parse("0/…")). For initialization from a snapshot, use copy_snapshot to obtain the consistent snapshot and slot, write bounded batches durably, then continue with AfterSnapshot(position); see initial snapshots. You can also call position.save_checkpoint(path) and continue in a new process with Resume. Resume requires an existing checkpoint and explicitly rejects corruption, identity mismatches and unrecoverable positions. It never silently falls back to the latest WAL position.

    #Guarantees and boundaries

    • Only committed transactions are delivered, preserving event order, table/type information, transaction IDs and WAL positions.
    • Null, Text and UnchangedToast represent SQL NULL, text and unchanged external fields. subscribe(..., binary=true) requests binary transfer; Binary(Bytes) retains original bytes for caller decoding with column OIDs. Text remains the default, and binary mode can still contain fallback text fields.
    • Standalone subscriptions may opt into protocol=V2Streaming, buffering uncommitted segments until commit. See API for resource and rollback contracts. The pipeline continues to use protocol v1.
    • ack advances only across a contiguous completed prefix. The checkpoint file, atomic replacement and parent directory must be synced before feedback changes. Received position is not business durability.
    • tx.id identifies a transaction; tx.event_id(index) identifies a data change. Repeated metadata does not change data-event IDs.
    • messages=true supports transaction-bound logical messages and a separate callback for nontransactional messages. Payload bytes remain unchanged; schema_snapshot interprets Supabase ETL DDL payloads. Pipeline schema history can be persisted with run_pipeline(..., schema_store=store); see API.
    • Custom Destination implementations integrate through copy_snapshot_to and sub.apply_to. Accepted never authorizes acknowledgement. A durable barrier is required for checkpoints/feedback, including empty flushes and normal drain.
    • Background heartbeats continue. Frames, transactions, metadata and outstanding queues have limits; exceeding them closes the connection without acknowledging.
    • SCRAM-SHA-256 and verified remote TLS are supported. Plaintext accepts only numeric loopback addresses. Initial passwords are printable ASCII; non-ASCII passwords requiring SASLprep are explicitly rejected.
    • run_pipeline maintains durable per-table states, concurrent independent snapshots, failed-copy restart and catch-up. Completed tables retain progress; full queues apply backpressure. Newly published tables are discovered and copied upon their first WAL event.
    • Value.decode_text(oid) returns typed Cells, supporting exact numbers, date/time, JSON, UUID, bytea and one-dimensional arrays. SQL NULL, JSON null and unchanged TOAST remain distinct. Unknown scalars retain text.
    • StateStore supports file and PostgreSQL backends for pipeline/subscription checkpoints and destination metadata. Table-copy errors persist and support timed or manual retries. See API.
    • ClickHouseDestination supports ReplacingMergeTree current-state views and MergeTree event histories, with snapshot/CDC writes, column DDL and durable recovery. See supported scope.
    • This module supports PostgreSQL → ClickHouse only. It excludes BigQuery, Snowflake and Iceberg. DuckLake is a roadmap item, not an implemented feature.
    • Automatic primary election and two-phase transactions are not provided. Schema support is destination-specific. Cross-system exactly-once delivery is not promised.

    replica identity controls old tuple availability. FULL supplies more old columns; default primary-key identity may supply only keys or no old tuple. UnchangedToast must not overwrite a business value with NULL. See API and support.

    #Local validation

    Known validation limitation: one macOS release ordinary-test run of the merged source reported TimeoutError in copy-exit cleanup and reconnect retry scenarios. Exactly one retry of that job passed with source, toolchain, commands and timeouts unchanged. The cause remains unconfirmed; this neither establishes nor fixes a product defect. See validation for deadlines, results and source binding.

    Use a dedicated Docker Compose project, binding database ports to 127.0.0.1:

    moon update docker compose -p mooncdc-test -f integration/compose.yaml up -d --wait moon run tools/setup-db.mbtx pg18 moon run tools/setup-db.mbtx pg17 moon check --target native --deny-warn moon test --target native moon run tools/setup-tls.mbtx pg18 moon run tools/setup-tls.mbtx pg17 MOONCDC_TEST_PORT=55418 MOONCDC_TEST_CA=.test-artifacts/tls-pg18/server.crt moon run tools/live-test.mbtx MOONCDC_TEST_PORT=55417 MOONCDC_TEST_CA=.test-artifacts/tls-pg17/server.crt moon run tools/live-test.mbtx moon run examples/index moon run examples/cache moon run tools/recovery-test.mbtx moon run tools/checkpoint-crash-test.mbtx

    Without MOONCDC_TEST_PORT, real database test bodies do not run; ordinary tests passing does not prove live validation. Setup scripts initialize isolated fixtures, not existing business databases. Fault tests terminate this project's walsenders or example child processes. See TESTING for commands, TLS and cleanup.

    #Documentation and maintenance

    See the standalone replicator for entrypoints and configuration.

    Apache-2.0; see LICENSE.

    Destination

    pub(open) trait Destination {
    fn supports_wal_batches(Self) -> Bool = _
    async fn write_wal_batch(Self, WalBatch) -> WriteStatus = _
    async fn bind_state(Self, StateSession) -> Unit = _
    async fn release_state(Self) -> Unit = _
    async fn bind_snapshot_schema(Self, Relation, SchemaSnapshot) -> Unit = _
    async fn startup(Self) -> Unit = _
    async fn shutdown(Self) -> Unit = _
    async fn schema_retention(Self, UInt) -> SchemaId? = _
    async fn reset_table(Self, Relation, attempt~ : String) -> Unit
    async fn write_rows(Self, Relation, ReadOnlyArray[ReadOnlyArray[Value]], TableCopyBatchId?) -> WriteStatus
    async fn finish_table_copy(Self, Relation) -> Unit = _
    async fn write_transaction(Self, Transaction) -> WriteStatus
    async fn flush(Self) -> Unit
    }

    Ordered destination contract. Implementations must tolerate replay and make flush a cumulative durability barrier. Owned tasks require cancellation cleanup.

    SchemaStore

    pub(open) trait SchemaStore {
    async fn get(Self, UInt, SchemaId) -> SchemaSnapshot?
    async fn all(Self) -> ReadOnlyArray[SchemaSnapshot]
    async fn put(Self, SchemaSnapshot) -> Unit
    async fn prune(Self, ReadOnlyArray[(UInt, SchemaId)]) -> Int
    }

    Persisted schemas must be visible in the cache only after durable storage succeeds.

    StateStore

    pub(open) trait StateStore {
    async fn acquire(Self, owner : String) -> Unit
    async fn release(Self, owner : String) -> Unit
    async fn load(Self, StateRecord) -> Bytes?
    async fn save(Self, owner : String, StateRecord, Bytes) -> Unit
    }

    One store instance/namespace owns one pipeline. acquire must exclude every other owner until release (including other processes). save must verify that owner, atomically persist all bytes, and return only after durability. A lost ownership/session must fail closed, never silently reconnect as the old owner. load returns an atomic snapshot and is also available to read-only observers.

    CdcError

    pub(all) suberror CdcError {
    Protocol(String)
    Conversion(String)
    Authentication(String)
    Server(String, String)
    InvalidConfig(String)
    LimitExceeded(String)
    UnsafeResume(String)
    CheckpointError(String)
    Closed
    } derive(
    Debug
    )

    Failures which require caller intervention; transport errors retain their original type.

    CdcError::to_repr

    TableReplicationError

    pub(all) suberror TableReplicationError {
    Retryable(String)
    Manual(String)
    Permanent(String)
    } derive(
    Debug
    )

    A destination may classify a failure explicitly. Copy failures use per-table retry; main apply replays from its checkpoint. Copy-side flush errors are fatal.

    ActivityKind

    pub(all) enum ActivityKind {
    InitialTableCopy
    WalApply(wal_sender_timeout_ms~ : UInt64)
    } derive(Eq,
    Debug
    )

    ActivityKind::equal

    ActivityKind::not_equal

    fn ActivityKind::not_equal(x : ActivityKind, y : ActivityKind) -> Bool

    ActivitySnapshot

    pub struct ActivitySnapshot {
    kind : ActivityKind
    inactive_ms : UInt64
    } derive(Eq,
    Debug
    )

    Activity is elapsed monotonic time, not durable destination progress.

    ActivitySnapshot::equal

    ActivitySnapshot::not_equal

    fn ActivitySnapshot::not_equal(x : ActivitySnapshot, y : ActivitySnapshot) -> Bool

    ApplyControl

    pub struct ApplyControl {
    // private fields
    }

    One-shot graceful stop signal. Stopping drains accepted destination writes; cancellation/failure instead leaves them unacknowledged for replay.

    ApplyControl::ApplyControl

    fn ApplyControl::ApplyControl() -> ApplyControl

    ApplyControl::activities

    fn ApplyControl::activities(self : ApplyControl) -> ReadOnlyArray[ActivitySnapshot]

    Approximate observations for this control's run_pipeline workers. Finished workers are absent; intentional source pauses do not accrue inactivity. A concurrent destination write/flush still accrues inactivity.

    ApplyControl::health

    fn ApplyControl::health(self : ApplyControl, stall_timeout_ms? : Int) -> PipelineHealth raise

    Read-only liveness/readiness policy matching the pinned ETL replicator. Initial copy can be ready; ready never means caught up or fully durable.

    ApplyControl::prometheus

    fn ApplyControl::prometheus(self : ApplyControl, pipeline_id? : String, destination? : String, project? : String, stall_timeout_ms? : Int) -> String raise

    Render this control's bounded Prometheus counters, histograms and live gauges. Counters include retries/replays and are not business exactly-once counts. Labels never include connection strings, relation names or error messages.

    ApplyControl::retry_table

    async fn ApplyControl::retry_table(self : ApplyControl, oid : UInt) -> Bool

    Retry a failed table on an active run_pipeline, using a fresh snapshot/reset. Returns false for unknown, healthy or NoRetry tables. A manual request resets the automatic retry budget. The control is usable only while the pipeline runs.

    ApplyControl::stop

    fn ApplyControl::stop(self : ApplyControl) -> Unit

    BatchConfig

    pub struct BatchConfig {
    memory_budget_ratio : Float
    max_bytes : UInt64
    max_fill_ms : Int
    }

    Advisory decoded-batch budget. One indivisible item can exceed the target.

    BatchConfig::new

    fn BatchConfig::new(memory_budget_ratio? : Float, max_bytes? : UInt64, max_fill_ms? : Int) -> BatchConfig

    Cell

    pub(all) enum Cell {
    SqlNull
    ToastUnchanged
    Bool(Bool)
    String(String)
    I16(Int16)
    I32(Int)
    I64(Int64)
    U32(UInt)
    F32(Float)
    F64(Double)
    Numeric(String)
    Date(PgDate)
    Time(PgTime)
    TimeTz(PgTime, offset_seconds~ : Int)
    Timestamp(PgTimestamp)
    TimestampTz(PgTimestamp)
    Uuid(Bytes)
    Json(Json)
    Bytes(Bytes)
    Array(ReadOnlyArray[Cell])
    } derive(
    Debug
    )

    Typed PostgreSQL text values. Numeric uses exact canonical decimal text and scale. Unknown scalar types retain text; TOAST is distinct from both SQL and JSON null. JSON numbers retain exact text in Number.repr; its Double is approximate. Cell equality compares that text recursively, including decimal scale.
    impl Eq for Cell

    Cell::equal

    fn Cell::equal(left : Cell, right : Cell) -> Bool

    Cell::not_equal

    fn Cell::not_equal(x : Cell, y : Cell) -> Bool

    Cell::to_repr

    Change

    pub(all) enum Change {
    RelationChanged(Relation)
    TypeChanged(TypeInfo)
    Insert(Relation, ReadOnlyArray[Value])
    Update(Relation, OldTuple?, ReadOnlyArray[Value])
    Delete(Relation, OldTuple)
    Truncate(ReadOnlyArray[Relation], cascade~ : Bool, restart_identity~ : Bool)
    Origin(Lsn, String)
    Message(LogicalMessage)
    } derive(Eq, ToJson,
    Debug
    )

    Change::equal

    fn Change::equal(Change, Change) -> Bool

    Change::not_equal

    fn Change::not_equal(x : Change, y : Change) -> Bool

    Change::to_json

    fn Change::to_json(Change) -> Json

    Change::to_repr

    ClickHouseDestination

    pub struct ClickHouseDestination {
    // private fields
    }

    Synchronous ClickHouse destination. Requires run_pipeline with a StateStore and the same SchemaStore supplied here. ReplacingMergeTree is the default. Supported schema transitions retain durable endpoints for interrupted DDL.

    ClickHouseDestination::bind_snapshot_schema

    async fn ClickHouseDestination::bind_snapshot_schema(self : ClickHouseDestination, relation : Relation, schema : SchemaSnapshot) -> Unit

    ClickHouseDestination::bind_state

    async fn ClickHouseDestination::bind_state(self : ClickHouseDestination, session : StateSession) -> Unit

    ClickHouseDestination::finish_table_copy

    async fn ClickHouseDestination::finish_table_copy(_self : ClickHouseDestination, _relation : Relation) -> Unit

    ClickHouseDestination::flush

    async fn ClickHouseDestination::flush(self : ClickHouseDestination) -> Unit

    ClickHouseDestination::new

    fn ClickHouseDestination::new(endpoint~ : String, user~ : String, password~ : String, database~ : String, publication~ : String, schema_store~ : &SchemaStore, engine? : ClickHouseEngine, max_insert_bytes? : Int, timeout_ms? : Int, connectivity_timeout_ms? : Int, schema_timeout_ms? : Int, ddl_timeout_ms? : Int, insert_timeout_ms? : Int, client_timeout_epsilon_ms? : Int) -> ClickHouseDestination raise

    The database must already exist. Credentials are sent in HTTP headers; HTTPS uses system trust. Use a dedicated StateStore namespace for this target.

    ClickHouseDestination::release_state

    async fn ClickHouseDestination::release_state(_self : ClickHouseDestination) -> Unit

    ClickHouseDestination::reset_table

    async fn ClickHouseDestination::reset_table(self : ClickHouseDestination, relation : Relation, attempt~ : String) -> Unit

    ClickHouseDestination::schema_retention

    async fn ClickHouseDestination::schema_retention(self : ClickHouseDestination, oid : UInt) -> SchemaId?

    ClickHouseDestination::shutdown

    async fn ClickHouseDestination::shutdown(self : ClickHouseDestination) -> Unit

    ClickHouseDestination::startup

    async fn ClickHouseDestination::startup(self : ClickHouseDestination) -> Unit

    ClickHouseDestination::supports_wal_batches

    fn ClickHouseDestination::supports_wal_batches(_self : ClickHouseDestination) -> Bool

    ClickHouseDestination::write_rows

    async fn ClickHouseDestination::write_rows(self : ClickHouseDestination, relation : Relation, rows : ReadOnlyArray[ReadOnlyArray[Value]], id : TableCopyBatchId?) -> WriteStatus

    ClickHouseDestination::write_transaction

    async fn ClickHouseDestination::write_transaction(self : ClickHouseDestination, tx : Transaction) -> WriteStatus

    ClickHouseDestination::write_wal_batch

    async fn ClickHouseDestination::write_wal_batch(self : ClickHouseDestination, batch : WalBatch) -> WriteStatus

    ClickHouseEngine

    pub(all) enum ClickHouseEngine {
    ReplacingMergeTree
    MergeTree
    } derive(Eq,
    Debug
    )

    ReplacingMergeTree exposes current state through a FINAL view; MergeTree retains insert/update/delete history. TRUNCATE clears either engine.

    ClickHouseEngine::equal

    ClickHouseEngine::not_equal

    fn ClickHouseEngine::not_equal(x : ClickHouseEngine, y : ClickHouseEngine) -> Bool

    Column

    pub struct Column {
    name : String
    type_oid : UInt
    type_modifier : Int
    key : Bool
    } derive(Eq, ToJson,
    Debug
    )

    Column::equal

    fn Column::equal(Column, Column) -> Bool

    Column::not_equal

    fn Column::not_equal(x : Column, y : Column) -> Bool

    Column::to_json

    fn Column::to_json(Column) -> Json

    Column::to_repr

    ColumnAlteration

    pub(all) enum ColumnAlteration {
    Rename
    DataType
    Nullability
    DefaultExpression
    } derive(Eq,
    Debug
    )

    ColumnAlteration::equal

    ColumnAlteration::not_equal

    fn ColumnAlteration::not_equal(x : ColumnAlteration, y : ColumnAlteration) -> Bool

    ColumnPresenceReason

    pub(all) enum ColumnPresenceReason {
    TableSchema
    Publication
    } derive(Eq,
    Debug
    )

    ColumnPresenceReason::equal

    ColumnPresenceReason::not_equal

    ConnectionConfig

    pub(all) struct ConnectionConfig {
    host : String
    hostaddr : String?
    port : Int
    user : String
    password : String
    database : String
    security : Security
    timeout_ms : Int
    keepalive : TcpKeepaliveConfig
    }

    Connection settings. Passwords are deliberately excluded from Debug output.

    ConnectionConfig::new

    fn ConnectionConfig::new(host~ : String, user~ : String, password? : String, database? : String, port? : Int, security? : Security, timeout_ms? : Int, hostaddr? : String, keepalive? : TcpKeepaliveConfig) -> ConnectionConfig raise

    Construct validated connection settings. host remains the TLS server name; optional numeric hostaddr overrides only the network destination.

    DestinationEvents

    pub struct DestinationEvents {
    commit_lsn : Lsn
    changes : ReadOnlyArray[Change]
    session : String
    // private fields
    }

    Read-only destination input. This view is not a transaction and cannot be acknowledged. A WAL fragment need not contain its source Commit boundary.

    DestinationEvents::event_id

    fn DestinationEvents::event_id(self : DestinationEvents, index : Int) -> String?

    DestinationEvents::replicated_schemas

    fn DestinationEvents::replicated_schemas(self : DestinationEvents, index : Int) -> ReadOnlyArray[ReplicatedSchema]

    Diagnostics

    pub struct Diagnostics {
    reconnects : Int
    received : Lsn
    durable : Lsn
    server_end : Lsn
    outstanding_transactions : Int
    queued_transactions : Int
    wal_lag_bytes : UInt64
    } derive(ToJson,
    Debug
    )

    Position and count diagnostics; WAL lag is an estimate, not unconsumed row count.

    Diagnostics::to_json

    fn Diagnostics::to_json(Diagnostics) -> Json

    FileStateStore

    pub struct FileStateStore {
    // private fields
    }

    Atomic records in an existing directory, protected by a process-wide file lock.

    FileStateStore::acquire

    async fn FileStateStore::acquire(self : FileStateStore, owner : String) -> Unit

    FileStateStore::load

    async fn FileStateStore::load(self : FileStateStore, key : StateRecord) -> Bytes?

    FileStateStore::new

    fn FileStateStore::new(directory : String) -> FileStateStore raise

    FileStateStore::release

    async fn FileStateStore::release(self : FileStateStore, owner : String) -> Unit

    FileStateStore::save

    async fn FileStateStore::save(self : FileStateStore, owner : String, key : StateRecord, bytes : Bytes) -> Unit

    IdentityKind

    pub(all) enum IdentityKind {
    Missing
    PrimaryKey
    FullRow
    AlternativeKey
    } derive(Eq,
    Debug
    )

    IdentityKind::equal

    IdentityKind::not_equal

    fn IdentityKind::not_equal(x : IdentityKind, y : IdentityKind) -> Bool

    InvalidatedSlotBehavior

    pub(all) enum InvalidatedSlotBehavior {
    RejectInvalidatedSlot
    RecreateInvalidatedSlot
    } derive(Eq,
    Debug
    )

    Reject lost WAL by default. Explicit recreation resynchronizes every table, honoring the configured initial-copy selection; it cannot restore lost WAL.

    InvalidatedSlotBehavior::equal

    InvalidatedSlotBehavior::not_equal

    LogicalMessage

    pub struct LogicalMessage {
    transactional : Bool
    lsn : Lsn
    prefix : String
    content : Bytes
    } derive(Eq, ToJson,
    Debug
    )

    Arbitrary pg_logical_emit_message payload. Content is not assumed to be UTF-8.

    LogicalMessage::equal

    LogicalMessage::not_equal

    fn LogicalMessage::not_equal(x : LogicalMessage, y : LogicalMessage) -> Bool

    LogicalMessage::schema_snapshot

    fn LogicalMessage::schema_snapshot(self : LogicalMessage, commit_lsn~ : Lsn, publication~ : String) -> SchemaSnapshot? raise

    Interpret the pinned Supabase ETL DDL payload. Unknown fields are ignored. Other prefixes/publications return None; malformed or nontransactional DDL fails.

    LogicalMessage::to_json

    Lsn

    pub struct Lsn {
    value : UInt64
    } derive(Compare, Eq, ToJson,
    Debug
    )

    An unsigned PostgreSQL WAL position.

    Lsn::compare

    fn Lsn::compare(Lsn, Lsn) -> Int

    Lsn::equal

    fn Lsn::equal(Lsn, Lsn) -> Bool

    Lsn::not_equal

    fn Lsn::not_equal(x : Lsn, y : Lsn) -> Bool

    Lsn::op_ge

    fn Lsn::op_ge(x : Lsn, y : Lsn) -> Bool

    Lsn::op_gt

    fn Lsn::op_gt(x : Lsn, y : Lsn) -> Bool

    Lsn::op_le

    fn Lsn::op_le(x : Lsn, y : Lsn) -> Bool

    Lsn::op_lt

    fn Lsn::op_lt(x : Lsn, y : Lsn) -> Bool

    Lsn::parse

    fn Lsn::parse(text : String) -> Lsn raise

    Parse the PostgreSQL hexadecimal high/low notation.

    Lsn::to_json

    fn Lsn::to_json(Lsn) -> Json

    Lsn::to_repr

    Lsn::to_string

    fn Lsn::to_string(self : Lsn) -> String

    MemoryBackpressureConfig

    pub struct MemoryBackpressureConfig {
    activate_threshold : Float
    resume_threshold : Float
    refresh_interval_ms : Int
    }

    Emergency source pausing. This does not reserve memory or change transaction limits. Defaults follow ETL; omit the run_pipeline option to disable it.

    MemoryBackpressureConfig::new

    fn MemoryBackpressureConfig::new(activate_threshold? : Float, resume_threshold? : Float, refresh_interval_ms? : Int) -> MemoryBackpressureConfig

    OldTuple

    pub(all) enum OldTuple {
    Key(ReadOnlyArray[Value])
    Full(ReadOnlyArray[Value])
    } derive(Eq, ToJson,
    Debug
    )

    OldTuple::equal

    fn OldTuple::equal(OldTuple, OldTuple) -> Bool

    OldTuple::not_equal

    fn OldTuple::not_equal(x : OldTuple, y : OldTuple) -> Bool

    OldTuple::to_json

    fn OldTuple::to_json(OldTuple) -> Json

    OldTuple::to_repr

    PgDate

    pub(all) enum PgDate {
    Finite(year~ : Int, month~ : Int, day~ : Int)
    PosInfinity
    NegInfinity
    } derive(Eq,
    Debug
    )

    PgDate::equal

    fn PgDate::equal(PgDate, PgDate) -> Bool

    PgDate::not_equal

    fn PgDate::not_equal(x : PgDate, y : PgDate) -> Bool

    PgDate::to_repr

    PgOutputProtocol

    pub(all) enum PgOutputProtocol {
    V1
    V2Streaming
    } derive(Eq,
    Debug
    )

    pgoutput v2 buffers streamed, possibly aborted transactions until Stream Commit. V1 remains the default and the pipeline protocol.

    PgOutputProtocol::equal

    PgOutputProtocol::not_equal

    fn PgOutputProtocol::not_equal(x : PgOutputProtocol, y : PgOutputProtocol) -> Bool

    PgTime

    pub struct PgTime {
    seconds : Int
    nanoseconds : Int
    } derive(Eq,
    Debug
    )

    seconds=86400 and nanoseconds=0 denotes the distinct 24:00:00 value. A leap second uses second 59 with nanoseconds in 1000000000..<2000000000.

    PgTime::equal

    fn PgTime::equal(PgTime, PgTime) -> Bool

    PgTime::not_equal

    fn PgTime::not_equal(x : PgTime, y : PgTime) -> Bool

    PgTime::to_repr

    PgTimestamp

    pub(all) enum PgTimestamp {
    Finite(date~ : PgDate, time~ : PgTime)
    PosInfinity
    NegInfinity
    } derive(Eq,
    Debug
    )

    Finite timestamps use astronomical years (1 BC = year 0). TimestampTz cells normalize finite values to UTC.

    PgTimestamp::equal

    fn PgTimestamp::equal(PgTimestamp, PgTimestamp) -> Bool

    PgTimestamp::not_equal

    fn PgTimestamp::not_equal(x : PgTimestamp, y : PgTimestamp) -> Bool

    PipelineHealth

    pub struct PipelineHealth {
    lifecycle : PipelineLifecycle
    live : Bool
    ready : Bool
    status : String
    } derive(Eq,
    Debug
    )

    PipelineHealth::equal

    PipelineHealth::not_equal

    fn PipelineHealth::not_equal(x : PipelineHealth, y : PipelineHealth) -> Bool

    PipelineLifecycle

    pub(all) enum PipelineLifecycle {
    Initializing
    Running
    Stopping
    } derive(Eq,
    Debug
    )

    PipelineLifecycle::equal

    PipelineLifecycle::not_equal

    fn PipelineLifecycle::not_equal(x : PipelineLifecycle, y : PipelineLifecycle) -> Bool

    PipelineStatus

    pub struct PipelineStatus {
    slot : String
    destination_id : String
    tables : ReadOnlyArray[TableSyncStatus]
    } derive(
    Debug
    )

    PostgresStateStore

    pub struct PostgresStateStore {
    // private fields
    }

    PostgreSQL durable state records. acquire creates the record table if needed and holds a session advisory lock for this namespace. It never reconnects a lost owner session; release and a new acquisition are required after failure.

    PostgresStateStore::acquire

    async fn PostgresStateStore::acquire(self : PostgresStateStore, owner : String) -> Unit

    PostgresStateStore::load

    async fn PostgresStateStore::load(self : PostgresStateStore, key : StateRecord) -> Bytes?

    PostgresStateStore::new

    fn PostgresStateStore::new(config : ConnectionConfig, store_id~ : String, schema? : String, table? : String, control? : ApplyControl) -> PostgresStateStore raise

    PostgresStateStore::release

    async fn PostgresStateStore::release(self : PostgresStateStore, owner : String) -> Unit

    PostgresStateStore::save

    async fn PostgresStateStore::save(self : PostgresStateStore, owner : String, key : StateRecord, bytes : Bytes) -> Unit

    Relation

    pub struct Relation {
    oid : UInt
    namespace_ : String
    name : String
    replica_identity : Byte
    columns : ReadOnlyArray[Column]
    } derive(Eq, ToJson,
    Debug
    )

    Immutable metadata snapshot attached to each row change.

    Relation::equal

    fn Relation::equal(Relation, Relation) -> Bool

    Relation::not_equal

    fn Relation::not_equal(x : Relation, y : Relation) -> Bool

    Relation::to_json

    fn Relation::to_json(Relation) -> Json

    Relation::to_repr

    ReplicatedSchema

    pub struct ReplicatedSchema {
    schema : SchemaSnapshot
    replicated : ReadOnlyArray[Bool]
    identity : ReadOnlyArray[Bool]
    } derive(Eq,
    Debug
    )

    Both masks have full-schema width. Identity is intersected with publication membership, independently of catalog primary-key membership and ordering.

    ReplicatedSchema::all_primary_keys_replicated

    fn ReplicatedSchema::all_primary_keys_replicated(self : ReplicatedSchema) -> Bool

    ReplicatedSchema::columns

    fn ReplicatedSchema::columns(self : ReplicatedSchema) -> ReadOnlyArray[SchemaColumn]

    ReplicatedSchema::decode_row

    fn ReplicatedSchema::decode_row(self : ReplicatedSchema, values : ReadOnlyArray[Value]) -> ReadOnlyArray[Cell] raise

    ReplicatedSchema::equal

    ReplicatedSchema::identity_kind

    fn ReplicatedSchema::identity_kind(self : ReplicatedSchema) -> IdentityKind

    ReplicatedSchema::new

    fn ReplicatedSchema::new(schema : SchemaSnapshot, replicated~ : ReadOnlyArray[Bool], identity~ : ReadOnlyArray[Bool]) -> ReplicatedSchema raise

    ReplicatedSchema::not_equal

    fn ReplicatedSchema::not_equal(x : ReplicatedSchema, y : ReplicatedSchema) -> Bool

    ReplicatedSchema::plan_change

    fn ReplicatedSchema::plan_change(self : ReplicatedSchema, after : ReplicatedSchema, map_name? : (String) -> String) -> SchemaPlan raise

    Plan a destination transition by physical column ordinal. Drops precede collision-free renames, additions, then type/nullability/default alterations. map_name must match the destination's creation and data-write name mapping. Primary-key changes are reported separately and never silently emitted as DDL.

    ReplicatedSchema::with_schema

    fn ReplicatedSchema::with_schema(self : ReplicatedSchema, schema : SchemaSnapshot) -> ReplicatedSchema raise

    Materialize a DDL snapshot using retained relation masks. A replacement wire relation must be used if column count/membership changes.

    SchemaColumn

    pub struct SchemaColumn {
    name : String
    type_oid : UInt
    type_modifier : Int
    ordinal : Int
    nullable : Bool
    primary_key_ordinal : Int?
    default_expression : String?
    } derive(Eq, ToJson,
    Debug
    )

    SchemaColumn::equal

    SchemaColumn::not_equal

    fn SchemaColumn::not_equal(x : SchemaColumn, y : SchemaColumn) -> Bool

    SchemaColumn::to_json

    SchemaId

    pub struct SchemaId {
    commit_lsn : Lsn
    message_lsn : Lsn
    } derive(Compare, Eq,
    Debug
    )

    Schema versions sort by transaction commit, then logical-message position.

    SchemaId::before_lsn

    fn SchemaId::before_lsn(position : Lsn) -> SchemaId raise

    Inclusive schema bound for an exclusive replication checkpoint.

    SchemaId::compare

    fn SchemaId::compare(SchemaId, SchemaId) -> Int

    SchemaId::equal

    fn SchemaId::equal(SchemaId, SchemaId) -> Bool

    SchemaId::not_equal

    fn SchemaId::not_equal(x : SchemaId, y : SchemaId) -> Bool

    SchemaId::op_ge

    fn SchemaId::op_ge(x : SchemaId, y : SchemaId) -> Bool

    SchemaId::op_gt

    fn SchemaId::op_gt(x : SchemaId, y : SchemaId) -> Bool

    SchemaId::op_le

    fn SchemaId::op_le(x : SchemaId, y : SchemaId) -> Bool

    SchemaId::op_lt

    fn SchemaId::op_lt(x : SchemaId, y : SchemaId) -> Bool

    SchemaId::to_repr

    SchemaOperation

    pub(all) enum SchemaOperation {
    DropColumn(SchemaColumn, reason~ : ColumnPresenceReason)
    AddColumn(SchemaColumn, reason~ : ColumnPresenceReason)
    AlterColumn(before~ : SchemaColumn, after~ : SchemaColumn, kind~ : ColumnAlteration)
    } derive(Eq,
    Debug
    )

    Alter changes exactly one field group; its before state includes earlier operations. Names have already been mapped to the destination namespace.

    SchemaOperation::equal

    SchemaOperation::not_equal

    fn SchemaOperation::not_equal(x : SchemaOperation, y : SchemaOperation) -> Bool

    SchemaPlan

    pub struct SchemaPlan {
    operations : ReadOnlyArray[SchemaOperation]
    primary_key_changed : Bool
    has_rename_cycles : Bool
    } derive(Eq,
    Debug
    )

    SchemaPlan::equal

    fn SchemaPlan::equal(SchemaPlan, SchemaPlan) -> Bool

    SchemaPlan::not_equal

    fn SchemaPlan::not_equal(x : SchemaPlan, y : SchemaPlan) -> Bool

    SchemaSnapshot

    pub struct SchemaSnapshot {
    id : SchemaId
    oid : UInt
    namespace_ : String
    name : String
    replica_identity : Byte
    columns : ReadOnlyArray[SchemaColumn]
    // private fields
    } derive(
    Debug
    )

    Full table schema; publication membership is separate from identity membership.

    SchemaSnapshot::equal

    fn SchemaSnapshot::equal(self : SchemaSnapshot, other : SchemaSnapshot) -> Bool

    SchemaSnapshot::from_json

    fn SchemaSnapshot::from_json(json : Json) -> SchemaSnapshot raise

    Reconstruct validated schema metadata and identity from the canonical envelope.

    SchemaSnapshot::not_equal

    fn SchemaSnapshot::not_equal(x : SchemaSnapshot, y : SchemaSnapshot) -> Bool

    SchemaSnapshot::project

    fn SchemaSnapshot::project(self : SchemaSnapshot, relation : Relation) -> ReplicatedSchema raise

    Build masks from the column membership and identity flags of a wire relation.

    SchemaSnapshot::relation

    fn SchemaSnapshot::relation(self : SchemaSnapshot, published : ReadOnlyArray[String]) -> Relation raise

    Rebuild the published view using the last pgoutput column membership mask. A fresh protocol Relation supersedes this fallback after publication changes.

    SchemaSnapshot::to_json

    fn SchemaSnapshot::to_json(self : SchemaSnapshot) -> Json

    Security

    pub(all) enum Security {
    LocalPlaintext
    VerifyFull
    VerifyCAFile(String)
    } derive(
    Debug
    )

    TLS always verifies the server certificate and hostname when enabled.

    Security::to_repr

    SnapshotEvent

    pub(all) enum SnapshotEvent {
    TableBegin(Relation)
    TableRows(Relation, ReadOnlyArray[ReadOnlyArray[Value]])
    TableEnd(Relation)
    } derive(
    Debug
    )

    TableBegin and TableEnd are delivered even for empty tables. Snapshot rows use text transfer; SQL NULL remains Null. Callbacks run sequentially with backpressure.

    SnapshotPosition

    pub struct SnapshotPosition {
    lsn : Lsn
    // private fields
    }

    Returned only after every snapshot callback succeeds. Keep target writes durable before returning from callbacks, then subscribe with AfterSnapshot(position).

    SnapshotPosition::save_checkpoint

    async fn SnapshotPosition::save_checkpoint(self : SnapshotPosition, path : String) -> Unit

    Persist a completed, business-durable snapshot handoff for a later Resume. The parent directory must exist; existing checkpoints are never overwritten.

    SnapshotPosition::save_checkpoint_in

    async fn SnapshotPosition::save_checkpoint_in(self : SnapshotPosition, store : &StateStore) -> Unit

    Start

    pub(all) enum Start {
    At(Lsn)
    AfterSnapshot(SnapshotPosition)
    Resume
    }

    A fresh explicit WAL position, or strict recovery from an existing checkpoint.

    StateRecord

    pub(all) enum StateRecord {
    Pipeline
    ReplicationCheckpoint
    Schemas
    TableMetadata(UInt)
    } derive(Eq,
    Debug
    )

    StateRecord::equal

    fn StateRecord::equal(StateRecord, StateRecord) -> Bool

    StateRecord::not_equal

    fn StateRecord::not_equal(x : StateRecord, y : StateRecord) -> Bool

    StateSession

    pub struct StateSession {
    // private fields
    }

    Valid only inside with_state_store or a pipeline's bind_state/startup lifetime.

    StateSession::check

    fn StateSession::check(self : StateSession) -> Unit raise

    Reject a session after its owning with_state_store scope has ended. Destinations must check before issuing external side effects.

    StateSession::get_metadata

    async fn StateSession::get_metadata(self : StateSession, table : UInt) -> Json?

    StateSession::put_metadata

    async fn StateSession::put_metadata(self : StateSession, table : UInt, value : Json) -> Unit

    Destination-owned metadata is scoped by this store's pipeline and source OID. Persist operation intent before external work and completion only after the corresponding destination operation is durable.

    Subscription

    pub struct Subscription {
    // private fields
    }

    A subscription lives only within subscribe's callback. Do not use it after return.

    Subscription::ack

    async fn Subscription::ack(self : Subscription, tx : Transaction) -> Unit

    Persist a contiguous acknowledgement prefix. Call only after business persistence. Later acknowledgements may be recorded without advancing the durable position.

    Subscription::apply_to

    async fn Subscription::apply_to(self : Subscription, destination : &Destination, control~ : ApplyControl, flush_every? : Int, flush_interval_ms? : Int) -> Unit

    Consume complete transactions in order. Call inside subscribe/with_destination; do not call next or ack concurrently. Stop drains accepted work before returning. Idle flushes prevent Accepted writes waiting indefinitely for another transaction.

    Subscription::close

    fn Subscription::close(self : Subscription) -> Unit

    Stop the stream and wake blocked consumers. Closing never acknowledges data.

    Subscription::diagnostics

    fn Subscription::diagnostics(self : Subscription) -> Diagnostics

    Subscription::next

    async fn Subscription::next(self : Subscription) -> Transaction

    Wait for the next complete committed transaction. Only one task may call next at a time.

    TableCopyBatchId

    pub struct TableCopyBatchId {
    attempt : String
    relation_id : UInt
    sequence : UInt64
    } derive(Eq, ToJson,
    Debug
    )

    Identity within a fresh snapshot attempt; retries must use the same batch ID. A new snapshot generates a new attempt and resets each destination table first.

    TableCopyBatchId::equal

    TableCopyBatchId::not_equal

    fn TableCopyBatchId::not_equal(x : TableCopyBatchId, y : TableCopyBatchId) -> Bool

    TableCopyBatchId::to_json

    TableRetryPolicy

    pub(all) enum TableRetryPolicy {
    NoRetry
    ManualRetry
    TimedRetry(UInt64)
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Persisted retry policy; TimedRetry uses Unix milliseconds.

    TableRetryPolicy::equal

    TableRetryPolicy::not_equal

    fn TableRetryPolicy::not_equal(x : TableRetryPolicy, y : TableRetryPolicy) -> Bool

    TableRetryPolicy::to_json

    TableSyncCopy

    pub(all) enum TableSyncCopy {
    IncludeAllTables
    SkipAllTables
    IncludeTables(ReadOnlyArray[UInt])
    SkipTables(ReadOnlyArray[UInt])
    } derive(Eq,
    Debug
    )

    Select initial rows by source table OID. Skipped tables still reset/create an empty destination, retain schemas and join WAL replication at their snapshot. Changes to this policy do not recopy tables that have already handed over.

    TableSyncCopy::equal

    TableSyncCopy::not_equal

    fn TableSyncCopy::not_equal(x : TableSyncCopy, y : TableSyncCopy) -> Bool

    TableSyncPhase

    pub(all) enum TableSyncPhase {
    Pending
    Copying
    Catchup(Lsn)
    Ready(Lsn)
    Errored(reason~ : String, retry~ : TableRetryPolicy, attempts~ : Int)
    } derive(Eq,
    Debug
    )

    Persisted table progress. Copying includes private-slot replay; Catchup/Ready retain the durable handover cutoff (initial snapshot or last private commit end).

    TableSyncPhase::equal

    TableSyncPhase::not_equal

    fn TableSyncPhase::not_equal(x : TableSyncPhase, y : TableSyncPhase) -> Bool

    TableSyncStatus

    pub struct TableSyncStatus {
    oid : UInt
    phase : TableSyncPhase
    } derive(
    Debug
    )

    TcpKeepaliveConfig

    pub(all) struct TcpKeepaliveConfig {
    idle_secs : Int
    interval_secs : Int
    retries : Int
    } derive(Eq,
    Debug
    )

    TCP probe settings in seconds, matching the pinned ETL replication defaults.

    TcpKeepaliveConfig::equal

    TcpKeepaliveConfig::new

    fn TcpKeepaliveConfig::new(idle_secs? : Int, interval_secs? : Int, retries? : Int) -> TcpKeepaliveConfig

    TcpKeepaliveConfig::not_equal

    Transaction

    pub struct Transaction {
    id : String
    xid : UInt
    commit_lsn : Lsn
    end_lsn : Lsn
    commit_time_us : Int64
    changes : ReadOnlyArray[Change]
    // private fields
    } derive(
    Debug
    )

    Complete committed transaction. Use event_id for stable row-event identity.

    Transaction::destination_events

    fn Transaction::destination_events(self : Transaction) -> DestinationEvents

    Transaction::event_id

    fn Transaction::event_id(self : Transaction, index : Int) -> String?

    Stable identity for a data change; metadata has no replay-stable ordinal. Relation/type announcements can be repeated differently after reconnect.

    Transaction::replicated_schemas

    fn Transaction::replicated_schemas(self : Transaction, index : Int) -> ReadOnlyArray[ReplicatedSchema]

    Exact per-event schemas resolved by a pipeline with a SchemaStore. Truncate returns one schema per relation; raw subscriptions and metadata return empty.

    Transaction::to_json

    fn Transaction::to_json(self : Transaction) -> Json

    TypeInfo

    pub struct TypeInfo {
    oid : UInt
    namespace_ : String
    name : String
    } derive(Eq, ToJson,
    Debug
    )

    TypeInfo::equal

    fn TypeInfo::equal(TypeInfo, TypeInfo) -> Bool

    TypeInfo::not_equal

    fn TypeInfo::not_equal(x : TypeInfo, y : TypeInfo) -> Bool

    TypeInfo::to_json

    fn TypeInfo::to_json(TypeInfo) -> Json

    TypeInfo::to_repr

    Value

    pub(all) enum Value {
    Null
    Text(String)
    Binary(Bytes)
    UnchangedToast
    } derive(Eq, ToJson,
    Debug
    )

    Raw transfer values preserve SQL NULL and unchanged out-of-line TOAST distinctly.

    Value::decode_text

    fn Value::decode_text(self : Value, type_oid : UInt, array_element_oid? : UInt) -> Cell raise

    Decode text with its PostgreSQL OID. Supply an element OID for catalog-discovered custom arrays. One-dimensional array lower bounds are discarded as in ETL.

    Value::equal

    fn Value::equal(Value, Value) -> Bool

    Value::not_equal

    fn Value::not_equal(x : Value, y : Value) -> Bool

    Value::to_json

    fn Value::to_json(Value) -> Json

    Value::to_repr

    WalBatch

    pub struct WalBatch {
    id : String
    xid : UInt
    commit_lsn : Lsn
    commit_time_us : Int64
    changes : ReadOnlyArray[Change]
    end_lsn : Lsn?
    // private fields
    } derive(
    Debug
    )

    Ordered pgoutput v1 fragment. Begin already identifies a committed source transaction, but only end_lsn=Some marks receipt of its validated Commit. A destination may own fragments before that boundary; no fragment alone authorizes a checkpoint. Replay uses the original transaction/event IDs.

    WalBatch::destination_events

    fn WalBatch::destination_events(self : WalBatch) -> DestinationEvents

    WalBatch::event_id

    fn WalBatch::event_id(self : WalBatch, index : Int) -> String?

    WalBatch::replicated_schemas

    fn WalBatch::replicated_schemas(self : WalBatch, index : Int) -> ReadOnlyArray[ReplicatedSchema]

    WalBatch::to_repr

    WriteStatus

    pub(all) enum WriteStatus {
    Accepted
    Durable
    } derive(Eq,
    Debug
    )

    Durable covers this write and all earlier Accepted writes on this destination. Accepted transfers ownership to the destination but never authorizes an ack.

    WriteStatus::equal

    fn WriteStatus::equal(WriteStatus, WriteStatus) -> Bool

    WriteStatus::not_equal

    fn WriteStatus::not_equal(x : WriteStatus, y : WriteStatus) -> Bool

    copy_snapshot

    async fn copy_snapshot(connection : ConnectionConfig, slot~ : String, publication~ : String, consume : async (SnapshotEvent) -> Unit, batch_rows? : Int, copy_connections? : Int, max_frame_bytes? : Int, max_batch_bytes? : Int, slot_failover? : Bool) -> SnapshotPosition

    Copy a publication from an exported consistent snapshot and retain its new persistent slot for incremental consumption. The slot must not already exist. On failure no position/checkpoint is published; the slot is retained for explicit operator recovery. Schema/publication changes during copying are unsupported.

    copy_snapshot_to

    async fn copy_snapshot_to(connection : ConnectionConfig, destination : &Destination, slot~ : String, publication~ : String, batch_rows? : Int, copy_connections? : Int, max_frame_bytes? : Int, max_batch_bytes? : Int, schema_store? : &SchemaStore, slot_failover? : Bool) -> SnapshotPosition

    Copy a new snapshot through a destination, fencing prior copy attempts and requiring a durable barrier before returning the WAL handoff position.

    pipeline_status

    async fn pipeline_status(path : String) -> PipelineStatus

    Read an atomic state snapshot without changing a running pipeline.

    run_pipeline

    async fn run_pipeline(connection : ConnectionConfig, destination : &Destination, publication~ : String, destination_id~ : String, control~ : ApplyControl, state_path? : String, state_store? : &StateStore, slot_prefix? : String, copy_concurrency? : Int, copy_connections_per_table? : Int, table_sync_monitor_refresh_interval_ms? : Int, batch_rows? : Int, schema_store? : &SchemaStore, table_retry_delay_ms? : Int, max_table_retries? : Int, table_sync_copy? : TableSyncCopy, source_migrations? : Bool, slot_failover? : Bool, invalidated_slot_behavior? : InvalidatedSlotBehavior, memory_backpressure? : MemoryBackpressureConfig, batch? : BatchConfig, memory_refresh_interval_ms? : Int) -> Unit

    Persist table synchronization using legacy files or an exclusive StateStore. Provide exactly one of state_path and state_store; keep store identity stable.

    run_source_migrations

    async fn run_source_migrations(connection : ConnectionConfig, control? : ApplyControl) -> Unit

    Install the pinned ETL source helpers and DDL event trigger. Requires an appropriately privileged primary connection. Physical standbys are skipped. Shares SQLx's database advisory lock, history schema and SHA-384 checksums; unrelated successful history versions are preserved. Each pending migration and its success record commit together. This does not install store tables. Use run_source_migrations(config) before acquiring state stores in schema etl, or run_pipeline(..., source_migrations=true) for library startup.

    state_store_status

    async fn state_store_status(store : &StateStore) -> PipelineStatus?

    Observe a store without acquiring pipeline ownership or changing records.

    subscribe

    async fn[T] subscribe(connection : ConnectionConfig, slot~ : String, publication~ : String, start~ : Start, consume : async (Subscription) -> T, checkpoint_path? : String, checkpoint_store? : &StateStore, max_frame_bytes? : Int, max_transaction_bytes? : Int, max_transaction_events? : Int, max_pending_transactions? : Int, max_metadata_entries? : Int, heartbeat_ms? : Int, max_reconnects? : Int, reconnect_delay_ms? : Int, binary? : Bool, messages? : Bool, protocol? : PgOutputProtocol, nontransactional_message? : async (LogicalMessage) -> Unit, backpressure? : Bool) -> T

    Bounded CDC subscription with a legacy checkpoint file or exclusive StateStore. Returning/raising cancels owned tasks, closes the socket and releases ownership.

    validate_metrics_listen_address

    fn validate_metrics_listen_address(address : String) -> Unit raise

    Validate a numeric IPv4 or unbracketed IPv6 metrics address without resolving DNS or creating a listener. The port is configured separately.

    with_destination

    async fn[T] with_destination(destination : &Destination, run : async () -> T) -> T

    Run startup, then user work, then shutdown on success. On failure, propagate immediately; destination owners must release/cancel their resources themselves.

    with_file_schema_store

    async fn[T] with_file_schema_store(path : String, identity~ : String, run : async (&SchemaStore) -> T) -> T

    Exclusive checksummed file store with bounded atomic writes. The identity binds source/publication/destination; keep it stable and never reuse a path for another source.

    with_health_server

    async fn[T] with_health_server(control : ApplyControl, run : async () -> T, port? : Int, stall_timeout_ms? : Int) -> T

    Serve read-only GET/HEAD /livez and /readyz for the lifetime of run. Binds before invoking run, including pipeline initialization. The listener accepts IPv4/IPv6 on all interfaces, falling back only for unsupported IPv6 sockets. Returning, failing or cancelling run closes the listener and its connections. Omit this wrapper to disable HTTP health; it never stops or resumes workers.

    with_metrics_server

    async fn[T] with_metrics_server(control : ApplyControl, run : async () -> T, port? : Int, listen_address? : String, pipeline_id? : String, destination? : String, project? : String, stall_timeout_ms? : Int) -> T

    Serve this control's Prometheus metrics on all paths except /health ("OK"). Binds IPv4/IPv6 before run and closes listener/connections on every exit. The endpoint has no worker-control side effects; HEAD omits the response body. Omitting listen_address preserves all-interface IPv4/IPv6 with IPv4 fallback. An explicit numeric address binds only that address, without family fallback.

    with_state_schema_store

    async fn[T] with_state_schema_store(state : &StateStore, identity~ : String, run : async (&SchemaStore) -> T) -> T

    Store schemas through an exclusively owned StateStore namespace. Use a different namespace from run_pipeline's state_store, since each scope owns its lease. File and PostgreSQL backends retain the same bounded, checksummed schema history. An escaped SchemaStore is closed when this callback exits.

    with_state_store

    async fn[T] with_state_store(store : &StateStore, run : async (StateSession) -> T) -> T