Skip to content

Advanced - State Processing#51

Merged
DamianSuess merged 10 commits intodevelopfrom
feature/48-Overhaul
Dec 30, 2025
Merged

Advanced - State Processing#51
DamianSuess merged 10 commits intodevelopfrom
feature/48-Overhaul

Conversation

@DamianSuess
Copy link
Contributor

@DamianSuess DamianSuess commented Dec 29, 2025

Details

This architecture update to advanced state processing overhauls the system, causing incompatibility with previous releases.

What do you get?

  • NEW: Async/await states out the box
    • When async/await isn't used, users must exit state method via, ``
  • NEW: DefaultStateTimeoutMs (default Timeout.Infinite)
    • Ensures there are no hung states waiting for a result; the show must go on!
  • Update: DefaultTimeoutMs renamed to DefaultCommandTimeoutMs to keep it separate from regular states.
  • Update: Improved Composite States - deep hierarchy nested states (aka: substate, child state, nested state)
    • Composite state calls OnEntering -> OnEnter, then the initial sub-state. Upon last sub-state, Composite's OnExit is called.
    • Last Sub-State informs parent of it's exiting result via Context.LastChildResult
  • Cleanup: Cleaning up test cases and reorganizing TestData for proper reuse. Old code preserved in comments for now.

Benefits

The core framework has been used by Fortune 500 companies, small businesses, robotic frameworks, and more. Now open sourced by Xeno Innovations, Inc.

Improvements over the years have ensured the simplicity and flexibility to scale projects from Proof-of-Concept -> Enterprise general availability.

Sample State Construction

    // ---[ Build MS DI =---
    var services = new ServiceCollection()
      // Register Services
      .AddLogging(b => b.AddSimpleConsole())
      .AddSingleton<IEventAggregator, EventAggregator>()
      .AddSingleton<IDataService, DataService>()

      // Register States
      .AddTransient<EntryInitState>()
      .AddTransient<FetchState>()
      .AddTransient<WaitForMessageState>()
      .AddTransient<WorkflowParent>()
      .AddTransient<DoneState>()
      .AddTransient<ErrorState>()
      .BuildServiceProvider();

    // Factory uses MS-DI to construct states
    // Any DI container can be passed into `ActivatorUtilities.CreateInstance(MY_CONTAINER HERE)`
    Func<Type, object?> factory = t => ActivatorUtilities.CreateInstance(services, t);
    var aggregator = services.GetRequiredService<IEventAggregator>();

    // Supply MS DI factory and aggregator to the state machine
    // Omit `factory` to not use dependency injection
    var machine = new StateMachine<StateId>(factory, aggregator)
    {
      DefaultTimeoutMs = 3000,
    };

    machine.RegisterState<EntryInitState>(StateId.EntryInit, onSuccess: StateId.WorkflowParent);

    machine.RegisterComposite<WorkflowParent>(
      stateId: StateId.WorkflowParent,
      initialChildStateId: StateId.Fetch,
      onSuccess: StateId.Done,
      onError: StateId.Error,
      onFailure: StateId.Error);
    machine.RegisterSubState<FetchState>(
      StateId.Fetch,
      parentId: StateId.WorkflowParent,
      onSuccess: StateId.WaitForMessage);
    machine.RegisterSubState<WaitForMessageState>(
      StateId.WaitForMessage,
      parentId: StateId.WorkflowParent);

    machine.RegisterState<DoneState>(StateId.Done, onSuccess: null);
    machine.RegisterState<ErrorState>(StateId.Error);

    // Without an aggregator, OnMessage won't be called; the command state will timeout in 3000ms:
    var run = machine.RunAsync(StateId.EntryInit, CancellationToken.None);

    await run;

@DamianSuess DamianSuess added this to the v2.0 milestone Dec 29, 2025
@DamianSuess DamianSuess self-assigned this Dec 29, 2025
@DamianSuess DamianSuess added the enhancement New feature or request label Dec 29, 2025
@DamianSuess DamianSuess linked an issue Dec 29, 2025 that may be closed by this pull request
@DamianSuess DamianSuess changed the title Advanced State Processing Advanced - State Processing Dec 29, 2025
…ock testing and cleanly define XML documentation without cluttering the StateMachine class. Added placeholder exceptions (commented out)
…eoutMs to DefaultCommandTimeout (no hanging allowed). Fixed last child transition typo. IState no longer requires StateId (use Context). Updated basic and composite state tests for revamped framework.
…dded test for HungStateAvoidance using DefaultStateTimeoutMs
…uild and run in-line (really not good for debugging). Added fluent test for basic states. Composite test checks all states are registered and in order.
@DamianSuess DamianSuess merged commit 19f8bbb into develop Dec 30, 2025
@DamianSuess DamianSuess deleted the feature/48-Overhaul branch December 30, 2025 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v2.0] Advanced State - Processing Framework

1 participant