Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

embedded_single_node

A one-node engine fronting a real Valkey, with every configuration knob spelled out explicitly instead of defaulted.

What it demonstrates

The full ServerBuilder chain for a realistic single node: a named pool, both listeners, a Valkey backend, datacenter and rack identity, a token, a request timeout, and gossip explicitly disabled.

#![allow(unused)]
fn main() {
use std::time::Duration;
use dynomite::conf::{ConfServer, DataStore};
use dynomite::embed::{Server, ServerBuilder};

let server: Server = ServerBuilder::new("dyn_o_mite")
    .listen("127.0.0.1:18102".parse()?)
    .dyn_listen("127.0.0.1:18101".parse()?)
    .data_store(DataStore::Valkey)
    .servers(vec![ConfServer::parse("127.0.0.1:6379:1 backend")?])
    .datacenter("dc-local")
    .rack("rack-local")
    .tokens_str("0")
    .timeout(Duration::from_secs(5))
    .enable_gossip(false)
    .build()?;

let handle = server.start().await?;
}

Note the two-step build/start here, in contrast to embedded_minimal's start_with. The Server value exists before it starts, which is the seam you use to wire up observability.

The example then reads a stats snapshot and shuts down, rather than blocking on Ctrl-C, so it terminates cleanly under cargo run:

#![allow(unused)]
fn main() {
let snap = handle.stats();
eprintln!("snapshot pool={} uptime={}s", snap.pool.name, snap.uptime);
handle.shutdown().await?;
}

The configuration, knob by knob

data_store(DataStore::Valkey)
Selects the RESP/Valkey backend protocol. See Redis / Valkey.
servers(["127.0.0.1:6379:1 backend"])
The backing store endpoint and weight; parsed by ConfServer::parse. The trailing name is a label.
datacenter / rack
This node's placement in the topology. Even a single node has a DC and rack because the consistency and replication logic is defined in those terms; see Replication and Consistency.
tokens_str("0")
The token this node owns on the ring. A lone node owns the whole ring, so any single token works; see The Ring.
enable_gossip(false)
There are no peers, so gossip has nothing to do. Turning it off keeps startup instant and the log quiet.

Design decisions and trade-offs

Road not taken: implicit topology

The builder does not infer datacenter, rack, or token. Dynomite makes placement explicit because getting it wrong silently changes where data lands -- an implicit default would hide a decision that has to be deliberate in any real cluster. The cost is a little more ceremony for a single node; the benefit is that the single-node config reads the same as a production one.

Fronting an existing Valkey (rather than the in-memory default) is the point of this example: it shows that the engine's job is orchestration, not storage. The backing store stays a plain Valkey that knows nothing about the ring.

When to use this pattern

As the starting point for any single-node embedding that fronts a real store, and as the template you extend by adding peers (see embedded_cluster3) and hooks (see Hooks and Traits).

Where to go next

  • embedded_cluster3 turns this into three cooperating nodes with a custom Datastore.
  • Configuration is the full reference for every knob shown here and many more.