From 33bd74405274be32a3bcc7b0f7e9c0b48f2e5b3e Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Mon, 1 Dec 2025 12:37:16 -0800 Subject: [PATCH] KL-8 modify action state internal behavior comments --- bin/core/src/helpers/action_state.rs | 73 ++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/bin/core/src/helpers/action_state.rs b/bin/core/src/helpers/action_state.rs index 24c69caca..c41c3e470 100644 --- a/bin/core/src/helpers/action_state.rs +++ b/bin/core/src/helpers/action_state.rs @@ -1,3 +1,16 @@ +//! # Action State Management +//! +//! This module provides thread-safe state management for resource exections. +//! It prevents concurrent execution of exections on the same resource using +//! a Mutex-based locking mechanism with RAII guards. +//! +//! ## Safety +//! +//! - Uses RAII pattern to ensure locks are always released +//! - Handles lock poisoning gracefully +//! - Prevents race conditions through per-resource locks +//! - No deadlock risk: each resource has independent locks + use std::sync::{Arc, Mutex}; use anyhow::anyhow; @@ -29,7 +42,16 @@ pub struct ActionStates { CloneCache>>, } -/// Need to be able to check "busy" with write lock acquired. +/// Thread-safe state container for resource executions. +/// +/// Uses a Mutex to prevent concurrent executions and provides +/// RAII-based locking through [UpdateGuard]. +/// +/// # Safety +/// +/// - Each resource has its own ActionState instance +/// - State is reset to default when [UpdateGuard] is dropped +/// - Lock poisoning error handling is handled gracefully with anyhow::Error #[derive(Default)] pub struct ActionState( Mutex, @@ -43,7 +65,7 @@ impl *self .0 .lock() - .map_err(|e| anyhow!("action state lock poisoned | {e:?}"))?, + .map_err(|e| anyhow!("Action state lock poisoned | {e:?}"))?, ) } @@ -52,14 +74,33 @@ impl self .0 .lock() - .map_err(|e| anyhow!("action state lock poisoned | {e:?}"))? + .map_err(|e| anyhow!("Action state lock poisoned | {e:?}"))? .busy(), ) } - /// Will acquire lock, check busy, and if not will - /// run the provided update function on the states. - /// Returns a guard that returns the states to default (not busy) when dropped. + /// Acquires lock, checks if resource is busy, and if not, + /// runs the provided update function on the states. + /// + /// Returns an `UpdateGuard` that automatically resets the state + /// to default (not busy) when dropped. + /// + /// # Errors + /// + /// Returns an error if: + /// - The lock is poisoned + /// - The resource is currently busy + /// + /// # Example + /// + /// ```rust + /// let guard = action_state.update(|state| { + /// *state = SomeNewState; + /// })?; + /// // State is locked and marked as busy + /// // ... perform work ... + /// drop(guard) // Guard is dropped, state returns to default + /// ``` pub fn update( &self, update_fn: impl Fn(&mut States), @@ -92,10 +133,22 @@ impl } } -/// When dropped will return the inner state to default. -/// The inner mutex guard must already be dropped BEFORE this is dropped, -/// which is guaranteed as the inner guard is dropped by all public methods before -/// user could drop UpdateGuard. +/// RAII guard that automatically resets the action state when dropped. +/// +/// # Safety +/// +/// The inner mutex guard is guaranteed to be dropped before this guard +/// is dropped, preventing deadlocks. This is ensured by all public methods +/// that create UpdateGuard instances. +/// +/// # Behavior +/// +/// When dropped, this guard will: +/// 1. Re-acquire the lock +/// 2. Call the provided return function (typically resetting to default) +/// 3. Release the lock +/// +/// If the lock is poisoned, an error is logged but the drop continues. pub struct UpdateGuard<'a, States: Default + Send + 'static>( &'a Mutex, Box,