OrdinateDB

Documentation

product Pre-releaseunwritten sections are marked

API guide · collectors

gRPC ingest

Overview

Use gRPC ingest to feed points and durable gap markers from a custom collector into OrdinateDB. It is the collector write boundary for resolving source identifiers, streaming durable batches, and obeying server backpressure.

Use the HTTP read APIs instead when you are consuming stored data.

Quick example

A minimal collector resolves source URIs, opens the bidirectional write stream, observes credit, and removes local WAL records only after a cumulative acknowledgement.

Transport-neutral collector loop

resolved = ResolveSeries({
  collector_id,
  source_uris
})

open Write stream with bearer metadata or mTLS
send no more than current credit_batches

for each sealed edge-WAL record:
  send WriteBatch(
    collector_id,
    session_epoch,
    sequence_number = wal_record.index,
    series,
    watermark_ns,
    collector_receipt_ns,
    stream_class
  )

for each WriteAck:
  delete WAL records through ack.sequence_number
  set send window to ack.credit_batches when present
  estimate clock skew from ack.server_time_ns

ResolveSeries supplies stable series UUIDs. Each WriteAck confirms the durable sequence boundary and updates the collector's send window when credit is present.

How it works

Custom collectors use package ordinate.ingest.v1. The shipped Ingest service has two RPCs:

Service definition

service Ingest {
  rpc Write(stream WriteBatch) returns (stream WriteAck);
  rpc ResolveSeries(ResolveSeriesRequest) returns (ResolveSeriesResponse);
}

Reference

ResolveSeries

Resolve source URIs through the server registry before writing. The request carries the collector identity and a batch of opaque source URIs; the response maps each known URI to its stable series UUID.

FieldNumberTypeMeaning
collector_id1stringCollector identity name.
source_uris2repeated stringSource URIs to resolve.

ResolveSeriesResponse.uri_to_series_uuid is protobuf field 1 with type map<string, string>.

Write stream lifecycle

Write is bidirectional streaming. A collector sends ordered WriteBatch messages and independently receives cumulative WriteAck messages. The sequence number is the durable edge-WAL record index. An acknowledgement means the server has durably committed through that sequence.

FieldNumberTypeMeaning
collector_id1stringMust remain constant and match the authenticated collector identity.
session_epoch2uint64Monotonic dedupe and fencing epoch.
sequence_number3uint64Durable, monotonic edge-WAL record index.
series4repeated SeriesPointsPoints and gaps grouped by series.
watermark_ns5int64Promise that no value below this UTC nanosecond will follow; zero means none.
collector_receipt_ns6int64Collector wall clock when the batch was sealed.
stream_class7StreamClassLIVE by default; BACKFILL receives lower credit.

SeriesPoints

FieldNumberTypeMeaning
series_uuid1stringTarget registered series UUID.
points2repeated PointTyped samples for the series.
gaps3repeated GapMarkerDurable edge-detected gaps.

Point

FieldNumberTypeMeaning
timestamp_ns1int64UTC Unix timestamp in nanoseconds.
value_f642doubleFloat64 value; preserves the original Phase 0 field number.
quality3uint32Source quality code.
value_f324floatFloat32 value.
value_i645sint64Signed integer value.
value_bool6boolBoolean value.
value_string7stringString value, limited to 65,536 bytes.
value_digital8DigitalValueOrdinal plus opaque enum-set reference.
Compatibility rule: an unset Point.value oneof means float64 zero. Early proto3 collectors omitted field 2 when the value was exactly 0.0; the server must not interpret that wire shape as “no value.”

DigitalValue

FieldNumberTypeMeaning
ordinal1sint64Digital state ordinal.
enum_set_ref2stringOpaque model-registry reference.

GapMarker

FieldNumberTypeMeaning
start_ns1int64Included start of the gap.
end_ns2int64Excluded end of the gap.
cause3GapCauseStructured gap cause.
detail4stringOptional free-text detail.

GapCause values are GAP_CAUSE_UNSPECIFIED, GAP_BUFFER_DROP_OLDEST, GAP_BUFFER_BLOCK_SOURCE, GAP_SOURCE_DISCONNECTED, and GAP_COLLECTOR_FAILOVER.

WriteAck and credit

FieldNumberTypeMeaning
sequence_number1uint64Cumulative durable commit position.
credit_batches2optional uint32Maximum outstanding batches: absent means unlimited; zero means pause.
server_time_ns3int64Server wall clock when the acknowledgement was sent.

The collector must not have more unacknowledged batches in flight than credit_batches. Live streams normally receive more credit than backfill streams. Disk-full state can reduce credit to zero; the server can later re-grant credit without advancing the acknowledged sequence. Treat the acknowledgement as cumulative and discard all local WAL records through its sequence number only after receiving it.

Epochs, reconnects, and status codes

  • Increase session_epoch when a new collector owner takes over. A higher epoch fences older streams.
  • FAILED_PRECONDITION containing stale session_epoch is a permanent fence for that epoch.
  • ABORTED denotes retryable admission conflicts such as a same-class reconnect race or full stream slots.
  • INVALID_ARGUMENT means the batch violates the ingest contract.
  • PERMISSION_DENIED includes a mismatch between the authenticated collector identity and collector_id.
  • INTERNAL reports an internal ingest or registry failure.

Common patterns

Authenticate a collector

Collectors can send a bearer service token or use mTLS. A bearer token belongs to a service identity whose name must exactly equal collector_id. For mTLS, the server matches a URI or DNS SAN to a kind=collector service identity. Token and mTLS paths coexist; neither is required while server auth is disabled or shadow. See authentication for token provisioning.

Reconnect without duplicating durable work

Reopen with the same owner epoch and resume after the last cumulative acknowledged sequence. Increase session_epoch only when a new collector owner takes over; the higher epoch fences older streams.

Related topics