Farsight Feeds

Architecture

Runtime layout — adapter crates, caches, streaming spine, and the planned scale topology.

Runtime Flow

flowchart LR
  upstream["Live upstream pollers<br/>(built-in + external)"] --> ingestor
  static["Bundled datasets"] --> adapter
  rss["RSS proxy & service APIs"] --> adapter
  ingestor["feed-ingestor<br/>(poll + normalize)"] --> spine["Zenoh spine<br/>(planned phase 3)"]
  ingestor --> hot["Dragonfly hot cache"]
  hot --> adapter["feed-api<br/>(HTTP + gRPC)"]
  spine --> adapter
  adapter --> trailbase["TrailBase<br/>(local SQLite cache)"]
  adapter --> questdb["QuestDB<br/>(history sink)"]
  adapter --> http["HTTP / GeoJSON / MVT"]
  adapter --> grpc["gRPC (incl. StreamLayer)"]
  http --> client["Map client / operator UI"]
  grpc --> client

The deployed adapter today serves from in-process snapshots and lazy-loaded static JSON. The planned scale split moves the polling layer into a sibling feed-ingestor crate and fans deltas through Zenoh; the read-API crate (feed-api) keeps the HTTP/gRPC surface stable across that move.

Crates

CrateRole
feed-apiHTTP + gRPC read API, operator control plane, alerts, vessels, analysis, satellites. Where every route in the OpenAPI lives.
feed-ingestor(in-flight) Polling sources, normalization, ingest into Dragonfly + Zenoh. Owns the satellite/cameras pollers moving out of feed-api.
feed-coreShared types, schemas, contract glue.
feed-storePersistence helpers (TrailBase, QuestDB sinks/rollups).

Ports

ServicePortPurpose
feed-api HTTP8080 (HTTP_BIND)Catalog, layers, datasets, operator, vessels, analysis, satellites, docs, Scalar, Farsight SPA.
feed-api gRPC50051 (GRPC_BIND)Read API + StreamLayer push.
trailbase4000 (host 4001)Local SQLite cache + admin UI.
Dragonflyenv (DRAGONFLY_URL)Hot snapshot cache (m0f.2, landed).
Zenoh spineenv (ZENOH_URL)Delta fan-out (m0f.4, landed; HTTP fan-out endpoints planned).
QuestDB ILPenv (QUESTDB_ILP_URL)Track-history sink + rollup jobs.
Envoy edgek8s ingressTLS + routing at farsight.r2d2.office.ilab.zone.

Cache semantics

  • Static datasets are shipped with the image — durable by construction.
  • Live snapshots live in process memory and (when DRAGONFLY_URL is set) in Dragonfly hot cache. Recovery on restart is sub-second.
  • TrailBase holds the localized SQLite mirror of every catalog dataset + generated geometry — see TrailBase Cache.
  • QuestDB holds track history and rollups (adsb_track_history, per-vessel windows) used by analysis endpoints; no-op without QUESTDB_ILP_URL.

Streaming reality check

The OpenAPI advertises HTTP streaming (/stream/{layer}, /ws/{layer}) and vector tiles (/tiles/{layer}/{z}/{x}/{y}.mvt) as x-status: planned. Neither is in the deployed image today. The gRPC StreamLayer RPC is the only push-style surface that works end-to-end right now.

See Tiles & Streaming for what to use in the meantime.

Deployment

The production deployment runs in the office k8s cluster (Helm overlay values.r2d2.yaml) with Envoy at the ingress and a Longhorn PVC mounted at /data for the local cache. The Scalar reference and Fumadocs site are served by the same adapter binary on the same port — no separate doc service.

On this page