Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Combining modules

Module constraints can be used together in one model. The job workload combines a finite-state lifecycle with bounded resource usage.

This example combines an FSM, event attributes, and measured resource usage. A worker publishes its thread limit. A job records how many threads it requests and how many it occupies while running.

YAML model

quent: alpha
model: job_workload

entities:
  Worker:
    # Generates WorkerUsage and WorkerBounds.
    resource:
      threads:
        kind: occupancy
        known-bounds: true
    events:
      ready:
        attributes:
          name: string
          limits: { sets-resource-bounds: true }

fsms:
  Job:
    states:
      queued:
        initial: true
        attributes:
          name: string
          requested_threads: u64
        to: [running]
      running:
        attributes:
          worker: { uses: Worker }
        to: [completed]
      completed: {}

Instrumentation API

The generated API distinguishes the worker’s WorkerBounds from the job’s WorkerUsage. No event names or payload keys are assembled at runtime.

// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

#[allow(unused)]
mod instrumentation {
    include!(concat!(env!("OUT_DIR"), "/job_workload.rs"));
}

use instrumentation::{Context, Job, JobWorkload, Noop, Worker, WorkerBounds, WorkerUsage};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let context = Context::<JobWorkload>::try_new(Noop)?;

    let mut worker = context.observer::<Worker>().handle();
    worker.ready("worker-1".to_owned(), WorkerBounds { threads: 16 })?;

    let _job = context
        .observer::<Job>()
        .handle()
        .queued("compile".to_owned(), 4)
        .running(worker.as_entity_ref_with(WorkerUsage { threads: 4 }))
        .completed();

    Ok(())
}
Key point

The job records its requested thread count and its usage of a bounded worker resource.

Check yourself

What does WorkerBounds { threads: 16 } represent?

Which call records where the job runs and how many threads it occupies?