Expand description
§dig-service
The generic orchestration scaffold every DIG Network binary shares.
Provides the minimal set of primitives needed to stand up a service:
the Service<N, A, R> composition, a TaskRegistry for tracked
tokio::spawn, a ShutdownToken broadcast, and three lifecycle
traits (NodeLifecycle, PeerApi, RpcApi).
§Design principle
Smallest possible shared foundation. This crate does NOT pull in:
- TOML / YAML config parsing — each binary defines its own config struct
via
serdeand hands a parsed instance toService::new. clap/ CLI framework — binaries build their own CLI.tracing_subscribersubscriber installation — each binary installs its subscriber inmain.rsbeforeService::start.- Prometheus / metrics exporters — wired in
main.rs. dig-rpcserver — plugged in throughRpcApi.- Peer transport — plugged in through
PeerApi.
Keeping this crate minimal means every downstream binary picks only the
pieces it needs. Introducers and relays get Service<N, A, ()> (peer-only);
daemons get Service<N, (), R> (RPC-only); fullnodes get all three slots.
§At a glance
apps/fullnode apps/validator apps/introducer apps/relay apps/daemon
│ │ │ │ │
└───────────────┴─────────┬───────┴──────────────┴─────────────┘
▼
dig-service ← this crate
│
▼
tokio + tokio-util§Minimal example
use async_trait::async_trait;
use dig_service::{
NodeLifecycle, Service, StartContext, RunContext, StopContext,
};
struct Node;
#[async_trait]
impl NodeLifecycle for Node {
const NAME: Option<&'static str> = Some("example");
async fn pre_start(&self, _ctx: &StartContext<'_>) -> anyhow::Result<()> { Ok(()) }
async fn on_start(&self, _ctx: &StartContext<'_>) -> anyhow::Result<()> { Ok(()) }
async fn run(&self, ctx: RunContext) -> anyhow::Result<()> {
// Block until shutdown is requested.
ctx.shutdown.cancelled().await;
Ok(())
}
async fn on_stop(&self, _ctx: &StopContext<'_>) -> anyhow::Result<()> { Ok(()) }
async fn post_stop(&self, _ctx: &StopContext<'_>) -> anyhow::Result<()> { Ok(()) }
}
let svc = Service::<Node, (), ()>::new(Node, (), ());
let _exit = svc.start().await.unwrap();§Lifecycle diagram
Service::start
│
▼
node.pre_start ◂── open stores, replay journal
│
▼
node.on_start ◂── bind ports, warm caches
│
▼
┌── node.run ──┐ ◂── main event loop; returns on shutdown
│ │
│ tasks.spawn… │
└────────┬───────┘
▼
tasks.join_all ◂── graceful wait w/ deadline
▼
node.on_stop ◂── flush stores
▼
node.post_stop ◂── close stores, release locks
▼
ExitStatus§Feature flags
| Flag | Default | Effect |
|---|---|---|
testing | off | Ships TestService + deterministic helpers |
tokio-console | off | Wires console_subscriber for live introspection |
structured-panic | off | Routes panics through tracing::error! and triggers Fatal shutdown |
Structs§
- Cancellation
Token - A token which can be used to signal a cancellation request to one or more tasks.
- Exit
Status - The final status returned by
Service::start. - Inbound
Message - A raw inbound peer-protocol message.
- Join
Handle - An owned permission to join on a task (await its termination).
- Peer
Info - Peer metadata populated at connect time.
- RunContext
- Context passed to
run. Differs fromStartContextonly in that it owns aTaskRegistry(spawning from insiderunis the common case). - Service
- The top-level orchestration handle.
- Service
Handle - A cheap-clone handle into a running
Service. - Shutdown
Token - A cancellation token with a typed
ShutdownReason. - Start
Context - Context passed to
pre_start/on_start. - Stop
Context - Context passed to
on_stop/post_stop. - Task
Registry - A clone-safe registry of spawned tasks.
- Task
Summary - Per-task snapshot surfaced by
TaskRegistry::snapshot.
Enums§
- Disconnect
Reason - Why a peer disconnected.
- Exit
Reason - Why the service exited.
- Service
Error - All failure modes of a running
Service. - Shutdown
Reason - Why the service is shutting down.
- Task
Kind - Kind of task, for observability.
Traits§
- Node
Lifecycle - The business-logic core of a service.
- PeerApi
- Peer-protocol dispatcher.
- RpcApi
- JSON-RPC dispatcher.