Module runtime

Module runtime 

Source
Expand description

High-level application facade.

Minimal builder API for constructing an AlloraRuntime from a configuration file. Intended for embedding with only a couple of lines of code.

§Quick Start

use allora_runtime::Runtime;
let rt = Runtime::new().run()?; // attempts to load ./allora.yml

§Overview

The builder exposes three operations:

  • new() – create a fresh builder (auto-discovery enabled)
  • with_config_file(path) – provide an explicit configuration file path
  • run() – build and return an AlloraRuntime

If no path is supplied, run() will try a sensible default (allora.yml). Errors surface via the returned Result.

§Custom Path

let rt = Runtime::new().with_config_file("examples/basic/helloworld/allora.yml").run()?;

§Service Wiring & The #[service] Macro

Services are described in configuration (YAML) under service-activator: blocks using a ref-name field. Example YAML fragment:

version: 1
service-activators:
  - ref-name: hello_world
    from: inbound.orders
    to: vetted.orders

At runtime, wiring matches each ref-name value against inventory descriptors submitted via the #[service] attribute macro. The macro registers a constructor closure that builds a single shared instance (singleton) of your type via its zero-arg new() and invokes its async process method.

§Using #[service]

Apply the attribute to an inherent impl block that contains a zero-arg new() method. If name is omitted the concrete type name (with spaces removed) is used.

Supported forms:

  • #[service] – implicit name = type name
  • #[service(name = "custom")] – explicit reference name matching YAML ref-name

Example:

use allora::{service, Service, Exchange, error::Result};
#[derive(Debug)]
struct Uppercase;
impl Uppercase { pub fn new() -> Self { Self } }
#[service(name="uppercase")]
impl Uppercase {}
#[async_trait::async_trait]
impl Service for Uppercase {
    async fn process(&self, exchange: &mut Exchange) -> Result<()> {
        if let Some(body) = exchange.in_msg.body_text() { exchange.out_msg = Some(Message::from_text(body.to_uppercase())); }
        Ok(())
    }
}

§Descriptor Wiring Criteria

A service is wired only if:

  1. Its ref-name matches a registered descriptor name.
  2. Both from and to channel IDs exist in the runtime.
  3. The inbound channel is currently a direct channel (other kinds may be supported later).

§Logging Fields

Structured fields emitted during build:

  • config.path / config.canonical – discovery details
  • service_activator.ref_name, inbound, outbound – wiring decisions
  • wired.count – number of services wired
  • channel.id, kind – registered channels
  • descriptor.impl (legacy field name in traces) now maps to descriptor name.

§Testing Notes

  • Use #tokio::test for async service wiring tests.
  • Macro UI tests (see tests/macro/) validate diagnostics & naming.
  • All services share a single instance; design internal mutability carefully.

Structs§

Runtime
Allora builder holds configuration inputs prior to runtime construction.

Functions§

wire_services