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

Self-loops

A direct self-loop transitions from a state back to itself, such as running → running. A state can also be part of an indirect cycle, such as running → paused → running. Both forms allow states on the cycle to be entered repeatedly, so their generated events have multi cardinality.

YAML model

quent: alpha
model: fsm_self_loop

fsms:
  Task:
    states:
      running:
        initial: true
        attributes:
          items_processed: u64
        to: [running, paused, completed]
      paused:
        to: [running]
      completed: {}

Instrumentation API

The task first repeats running through its direct self-loop. It then follows the indirect cycle through paused and back to running before entering completed once.

// 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"), "/fsm_self_loop.rs"));
}

use instrumentation::{Context, FsmSelfLoop, Noop, Task};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let context = Context::<FsmSelfLoop>::try_new(Noop)?;
    let task = context.observer::<Task>().handle().running(0);

    // Direct self-loop: running -> running.
    let task = task.running(64);
    // Indirect cycle: running -> paused -> running.
    let task = task.paused().running(128);
    let _task = task.completed();

    Ok(())
}
Key point

Every state on a direct or indirect cycle has a repeatable state-entry event.

Check yourself

Which transition is a direct self-loop?

Why does paused have multi cardinality?