pub trait JanusService:
Send
+ Sync
+ 'static {
// Required methods
fn name(&self) -> &str;
fn run<'life0, 'async_trait>(
&'life0 self,
cancel: CancellationToken,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
// Provided method
fn restart_policy(&self) -> RestartPolicy { ... }
}Expand description
The core trait every supervised service must implement.
§Example
use janus_core::supervisor::{JanusService, RestartPolicy};
use tokio_util::sync::CancellationToken;
use std::sync::atomic::{AtomicU64, Ordering};
pub struct MarketDataFeed {
exchange: String,
polls: AtomicU64,
}
#[async_trait::async_trait]
impl JanusService for MarketDataFeed {
fn name(&self) -> &str {
"market-data-feed"
}
fn restart_policy(&self) -> RestartPolicy {
RestartPolicy::OnFailure
}
async fn run(&self, cancel: CancellationToken) -> anyhow::Result<()> {
loop {
tokio::select! {
_ = cancel.cancelled() => {
tracing::info!("Market data feed shutting down");
break;
}
_ = self.poll_exchange() => {
self.polls.fetch_add(1, Ordering::Relaxed);
}
}
}
Ok(())
}
}
impl MarketDataFeed {
async fn poll_exchange(&self) {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
}Required Methods§
Sourcefn name(&self) -> &str
fn name(&self) -> &str
Returns the unique name of the service for logging, metrics, and supervisor identification.
This name is used in:
tracingspans (service = name)- Prometheus metric labels (
janus_supervisor_restarts_total{service="..."}) - The supervisor’s internal service registry
Sourcefn run<'life0, 'async_trait>(
&'life0 self,
cancel: CancellationToken,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn run<'life0, 'async_trait>(
&'life0 self,
cancel: CancellationToken,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
The main execution loop of the service.
This method should run until either:
- The service completes its work naturally (returns
Ok(())) - The
canceltoken is cancelled (graceful shutdown) - An unrecoverable error occurs (returns
Err(...))
§Cancellation Contract
Implementations must select on cancel.cancelled() in their main
loop. Failure to do so will cause the service to hang during shutdown,
ultimately hitting the supervisor’s shutdown timeout.
async fn run(&self, cancel: CancellationToken) -> anyhow::Result<()> {
loop {
tokio::select! {
_ = cancel.cancelled() => break,
result = self.do_work() => {
result?;
}
}
}
Ok(())
}§Interior Mutability
Because run() takes &self, services that need to track mutable
state (e.g., restart counters, connection handles) should use
interior mutability primitives like AtomicU64,
Mutex, or RwLock.
This is consistent with the Send + Sync requirements and allows
services to be wrapped in Arc or composed without requiring
exclusive ownership.
§Errors
Returning an error signals the supervisor that the service has failed.
The supervisor will then apply the service’s RestartPolicy and
backoff strategy to decide whether and when to restart.
Provided Methods§
Sourcefn restart_policy(&self) -> RestartPolicy
fn restart_policy(&self) -> RestartPolicy
The restart policy for this service.
Defaults to RestartPolicy::OnFailure, meaning the supervisor will
restart the service if run() returns an Err, but will treat a
clean Ok(()) exit as intentional completion.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".