Skip to main content

Ingest Pipeline

The ingest service is a Node.js application that processes robot telemetry from MQTT and stores it in MongoDB. It uses a pluggable module architecture for extensibility.

Entry Point​

The service starts in ingest/src/main.js, which initializes core managers and loads modules:

Ingest Service Startup
├── MongoManager.init() → Connect to MongoDB
├── PeerClient.init() → Connect to web app Peer API
├── UpstreamModule → (if enabled) loaded before OroMqtt.run() so
│ retained state messages forward on connect
├── OroMqtt.run() → Connect to MQTT broker
├── DerivedAttributesService → Worker queue for derived attributes
└── Load modules:
├── BasicsModule
├── SystemModule
├── CustomDataModule
├── RobotEventsModule
├── DiagnosticsModule
├── CustomCommandsModule
└── RobotLocalizationModule

Core Managers​

MongoManager​

Manages MongoDB connections and provides database access to all modules.

OroMqtt​

MQTT client wrapper that connects to the broker as the ingest master user. Provides topic subscription and message routing to modules via registerListener(subtopic, handler).

OroMqtt also owns a few built-in handlers of its own: echo (command callback resolution), logfiles_update (agent log file metadata → robot_agent_files), odometry (ros/odometry/+ → speed/distance attributes, when mqtt.odometryEnabled is true, the default), and system-wide system/<subtopic> topics.

PeerClient​

HTTP client for communicating with the web app's internal Peer API. Used for:

  • Creating and resolving alerts from attribute status changes (createAlert, resolveAlert → POST /peer/alerts)
  • Relaying robot commands received on out_cmd (robotCommand → POST /peer/robot/command)

Module Architecture​

Each ingest module follows a consistent pattern:

class MyModule {
constructor({ mqtt, mongo, ... }) {
this.mqtt = mqtt;
// Store references to shared managers
}

load(settings) {
// Register a listener for a subtopic; OroMqtt subscribes to
// r/+/<subtopic> and routes matching messages here
this.mqtt.registerListener('my_topic', this.handleMessage);
}

handleMessage(robotId, message, packet) {
// 1. Decode protobuf message
// 2. Transform/validate data
// 3. Write to MongoDB
}
}

Module Lifecycle​

  1. Constructor — receives shared managers (MQTT client, Mongo, etc.)
  2. load() — subscribes to MQTT topics and registers handlers; optionally accepts per-module settings
  3. Message handling — processes incoming messages and writes to MongoDB

Active Modules​

ModuleMQTT TopicsMongoDB CollectionDescription
BasicsModulestate, out_cmdrobotsRobot identity, version, online status; routes outbound commands
SystemModulesystem/statsattr_valuesCPU, RAM, disk, network metrics (via AttributesManager)
CustomDataModulecustomcustom_data, robot_key_valuesKey-value pairs, text, images
DiagnosticsModuleros/diagnostics2, ros/diagnostics/statusdiagnosticsROS hardware diagnostics, severity-based status
RobotEventsModuleeventsattr_values, robot_key_valuesSampled key-value events mapped to attributes
CustomCommandsModulecustom_command/script/statuscustom_scriptCommand/action execution feedback
RobotLocalizationModuleros/loc/* (pose, map, path, costmap, ...)localization, spatial_annotationsPose, maps, lasers, paths, costmaps
UpstreamModuleall robot topics (when enabled)upstream_mqtt_credentials, event_logForwards telemetry to an upstream ORO/InOrbit — see Upstream Forwarding

Module Settings​

Per-module configuration can be provided via the modules key in ingest/settings.json:

{
"modules": {
"robotLocalization": {
// Localization-specific settings
},
"diagnostics": {
// Diagnostics-specific settings
}
}
}

Two related settings live elsewhere: the odometry toggle is mqtt.odometryEnabled (under the mqtt key), and upstream forwarding is configured under the top-level upstream key (see Upstream Forwarding). Remember that ingest/settings.json is generated by Terraform — persistent changes belong in terraform/ (see Deployment).

Derived Attributes Service​

In addition to MQTT-driven modules, the ingest service runs a DerivedAttributesService worker that recomputes derived attributes on every source attribute update (event-driven via an in-memory work queue). Derived attributes are configured via the ConfigAPI; see ConfigAPI.

Data Processing Flow​

MQTT Message Received
│
├── Extract robotId from topic
│
├── Decode protobuf message
│ (using shared proto definitions)
│
├── Transform & validate
│ (module-specific logic)
│
├── Write to MongoDB
│ (upsert into appropriate collection)
│
└── Optional: Notify PeerClient
(trigger UI updates or commands)

Shared Utilities​

The ingest service includes shared code in ingest/src/shared/ (generated — copied from app/ by ingest/import.sh on each start):

  • oro.proto — Protocol Buffer definitions
  • constants.js — collection and module name constants
  • attributes.js — vital attribute ids and data-source types
  • Crypto, timeseries, geometry, and array utilities

Graceful Shutdown​

The ingest service traps SIGHUP, SIGINT, and SIGTERM signals for clean shutdown:

  1. Disconnect MQTT client
  2. Close MongoDB connections
  3. Exit process

Next Steps​