Pipeline.Safety.RecursionGuard (pipeline v0.0.1)
View SourceRecursion protection and circular dependency detection for nested pipelines.
Provides safety mechanisms to prevent infinite recursion and detect circular dependencies in nested pipeline execution chains.
Summary
Functions
Build the execution chain from the current context up to the root.
Perform all safety checks for nested pipeline execution.
Check for circular dependencies in the execution chain.
Check if the current execution context violates recursion limits.
Count the total number of steps across all nested pipelines.
Create a new execution context for a nested pipeline.
Log safety check results with appropriate log level.
Types
@type check_result() :: :ok | {:error, String.t()}
@type execution_context() :: %{ nesting_depth: non_neg_integer(), pipeline_id: String.t(), parent_context: execution_context() | nil, step_count: non_neg_integer() }
@type safety_limits() :: %{ max_depth: non_neg_integer(), max_total_steps: non_neg_integer() }
Functions
@spec build_execution_chain(execution_context()) :: [String.t()]
Build the execution chain from the current context up to the root.
Parameters
context
: The current execution context
Returns
- List of pipeline IDs in the execution chain
@spec check_all_safety(String.t(), execution_context()) :: check_result()
Perform all safety checks for nested pipeline execution.
Parameters
pipeline_id
: The ID of the pipeline about to be executedcontext
: The current execution contextlimits
: Safety limits configuration (optional)
Returns
:ok
if all checks pass{:error, message}
if any check fails
@spec check_all_safety(String.t(), execution_context(), safety_limits()) :: check_result()
@spec check_circular_dependency(String.t(), execution_context()) :: check_result()
Check for circular dependencies in the execution chain.
Parameters
pipeline_id
: The ID of the pipeline about to be executedcontext
: The current execution context
Returns
:ok
if no circular dependency detected{:error, message}
if circular dependency found
Examples
iex> context = %{pipeline_id: "parent", parent_context: nil}
iex> Pipeline.Safety.RecursionGuard.check_circular_dependency("child", context)
:ok
iex> parent = %{pipeline_id: "parent", parent_context: nil}
iex> child = %{pipeline_id: "child", parent_context: parent}
iex> Pipeline.Safety.RecursionGuard.check_circular_dependency("parent", child)
{:error, "Circular dependency detected: parent → child → parent"}
@spec check_limits(execution_context()) :: check_result()
Check if the current execution context violates recursion limits.
Parameters
context
: The current execution contextlimits
: Safety limits configuration (optional)
Returns
:ok
if all checks pass{:error, message}
if limits are exceeded
Examples
iex> context = %{nesting_depth: 2, pipeline_id: "test", parent_context: nil, step_count: 5}
iex> Pipeline.Safety.RecursionGuard.check_limits(context)
:ok
iex> context = %{nesting_depth: 15, pipeline_id: "test", parent_context: nil, step_count: 5}
iex> Pipeline.Safety.RecursionGuard.check_limits(context)
{:error, "Maximum nesting depth (10) exceeded: current depth is 15"}
@spec check_limits(execution_context(), safety_limits()) :: check_result()
@spec count_total_steps(execution_context()) :: non_neg_integer()
Count the total number of steps across all nested pipelines.
Parameters
context
: The current execution context
Returns
- Total number of steps
@spec create_execution_context( String.t(), execution_context() | nil, non_neg_integer() ) :: execution_context()
Create a new execution context for a nested pipeline.
Parameters
pipeline_id
: The ID of the pipelineparent_context
: The parent execution context (optional)step_count
: The number of steps in this pipeline (default: 0)
Returns
- New execution context
@spec log_safety_check(check_result(), String.t(), execution_context()) :: :ok
Log safety check results with appropriate log level.
Parameters
check_result
: The result of safety checkspipeline_id
: The ID of the pipeline being checkedcontext
: The current execution context