Skip to content

The Node

A node is a running instance of the framework. Think of it as the container that holds everything together — the event loop, the listeners, the state, and the mesh connections. You interact with it through framework::app, which creates and manages a node internally.

What a Node Does

  • Accepts incoming client connections (HTTP, WebSocket, TCP)
  • Connects to other nodes in the mesh
  • Runs the event loop that processes all I/O
  • Manages graceful startup and shutdown

Starting a Node

Creating a framework::app internally creates and initializes a node:

cpp
#include <framework.hpp>

using namespace framework;

int main() {
    framework::app app;
    // ... configure routes, handlers, services ...
    app.run();  // blocks until SIGINT/SIGTERM
}

The node is not a class you instantiate directly — it is created and owned by framework::app.

Node Identity

Every node has a unique UUID assigned at startup. You can access it through the state:

cpp
auto& node_id = app.get_state()->get_id();
// → "a1b2c3d4-... (UUID)"

The UUID is generated randomly at each startup and is not persisted across restarts. It is used for node identification within the mesh during a single session.

Note: Since the UUID changes on every restart, the vector clock system will treat a restarted node as a brand-new peer. Cache consistency and conflict resolution are unaffected, but long-lived node references in your application code should use a stable identifier (e.g., hostname) instead of the UUID.

Node Ports

A node can listen on multiple ports, each configured independently:

  • Client port (ports_.client_port_) — serves HTTP, WebSocket, and TCP connections. Default is 0 (no auto-start). You must call run_http_service(port), run_websocket_service(port), or run_tcp_service(port) explicitly to start listeners.
  • Node port (ports_.node_port_) — handles inter-node mesh traffic. Default is 10000. Used when run_mesh() is called.

If you only need HTTP, you only need to configure the client port and call run_http_service(). The node port is only required for mesh networking.

Lifecycle

The node (via app.run()) progresses through these phases:

  1. Initialization — Configuration is loaded, listeners are created, WAL is initialized. Boot callbacks registered via on_boot() fire after initialization.
  2. Connection — If seed configuration is set, the node connects to the seed and discovers peers in the mesh.
  3. Running — The event loop processes connections and messages. Background timers run for metrics collection, gossip failure detection, and Raft consensus heartbeats.
  4. Shutdown — On SIGINT, SIGTERM, or app.stop(), all listeners close, connections drain gracefully, timers are cancelled, and state is flushed.

Connecting to a Specific Node

For advanced mesh topologies, you can connect to a node directly without seed discovery:

cpp
// Available internally in the node implementation
// node.connect_to_node("10.0.0.5", 10001);

This is used by the gossip engine and Raft to establish peer connections discovered through the mesh.


Next: The App — the user-friendly interface to the node.