aion-server 0.30.0

Aion workflow server library: HTTP, gRPC, WebSocket, and worker endpoints. Run it with the `aion` binary from the aion-cli crate.
Documentation
//! The server state the auto-provision cells run against: one worker
//! deployment store, a supervisor that spawns a stand-in worker under a
//! temporary home, and an outbox the caller chooses.

use std::num::NonZeroU32;
use std::path::Path;
use std::sync::Arc;
use std::time::Duration;

use aion_store::{InMemoryStore, WorkerDeploymentStore};

use crate::config::{NamespaceMode, OutboxConfig, OutboxTransport};
use crate::worker::supervisor::{ManagedExecutable, SupervisionPolicy};
use crate::{NamespaceResolver, ServerState, StaticScheduleNamespaces, StaticWorkflowNamespaces};

/// An outbox a built-in agent worker could dial.
pub(super) fn liminal_outbox() -> OutboxConfig {
    OutboxConfig {
        enabled: true,
        transport: OutboxTransport::Liminal,
        liminal_listen_address: Some("127.0.0.1:50061".to_owned()),
        ..OutboxConfig::default()
    }
}

/// A restart policy short enough for a cell to watch.
pub(super) fn policy() -> Result<SupervisionPolicy, &'static str> {
    Ok(SupervisionPolicy {
        restart_backoff_initial: Duration::from_millis(20),
        restart_backoff_max: Duration::from_millis(20),
        restart_backoff_multiplier: NonZeroU32::new(1).ok_or("multiplier")?,
        restart_window: Duration::from_secs(600),
        max_restarts_per_window: NonZeroU32::new(5).ok_or("budget")?,
        stop_grace: Duration::from_secs(2),
    })
}

/// The executable the supervisor runs in place of a real worker: it sleeps.
pub(super) fn stand_in_worker(
    home: &Path,
) -> Result<ManagedExecutable, Box<dyn std::error::Error>> {
    let path = home.join("stand-in-worker");
    std::fs::write(&path, "#!/bin/sh\nexec sleep 300\n")?;
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt as _;
        std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o700))?;
    }
    Ok(ManagedExecutable::Path(path))
}

/// A server state over `store`, its supervisor commissioned under `home` when
/// asked, with deploys enabled and auth off.
pub(super) fn state_over(
    store: Arc<InMemoryStore>,
    outbox: OutboxConfig,
    commissioned: bool,
    home: &Path,
) -> Result<ServerState, Box<dyn std::error::Error>> {
    let resolver = NamespaceResolver::authorization_only(
        NamespaceMode::SharedEngine,
        StaticWorkflowNamespaces::default(),
        StaticScheduleNamespaces::default(),
    );
    let mut runtime = crate::api::http::test_support::runtime_config();
    runtime.auth.enabled = false;
    runtime.deploy.enabled = true;
    runtime.outbox = outbox;
    let namespace_store: Arc<dyn aion_store::NamespaceStore> = store.clone();
    let worker_store: Arc<dyn WorkerDeploymentStore> = store;
    let state = ServerState::from_parts_with_control_stores(
        resolver,
        runtime,
        namespace_store,
        worker_store,
    );
    if commissioned
        && !state
            .worker_supervisor()
            .commission(policy()?, stand_in_worker(home)?)
    {
        return Err("the supervisor was already commissioned".into());
    }
    Ok(state)
}