Skip to main content

JanusService

Trait JanusService 

Source
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§

Source

fn name(&self) -> &str

Returns the unique name of the service for logging, metrics, and supervisor identification.

This name is used in:

  • tracing spans (service = name)
  • Prometheus metric labels (janus_supervisor_restarts_total{service="..."})
  • The supervisor’s internal service registry
Source

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:

  1. The service completes its work naturally (returns Ok(()))
  2. The cancel token is cancelled (graceful shutdown)
  3. 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§

Source

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".

Implementors§