documentation/cheatsheet.cheatmd

# Reactor Process Cheatsheet

Process and supervisor management for [Reactor](https://hex.pm/packages/reactor) workflows.

## Basic Usage {: .col-2}

### Extension Setup

```elixir
defmodule MyReactor do
  use Reactor, extensions: [Reactor.Process]

  # Your reactor steps here
end
```

### Child Specification

```elixir
# Simple module child spec
child_spec :worker_spec do
  module MyWorker
end

# Module with options
child_spec :server_spec do
  module {MyServer, [port: 4000]}
end

# Dynamic child spec with transform
child_spec :dynamic_spec do
  module input(:base_module)
  transform fn {mod, opts}, inputs ->
    {mod, Keyword.put(opts, :name, inputs.worker_name)}
  end
end
```

## Process Lifecycle {: .col-2}

### Starting Processes

```elixir
# Start and link a process
start_link :worker do
  child_spec result(:worker_spec)
end

# Start child under supervisor
start_child :server do
  supervisor input(:my_supervisor)
  child_spec result(:server_spec)
end

# Don't fail if already started
start_child :idempotent_worker do
  supervisor input(:supervisor)
  child_spec result(:worker_spec)
  fail_on_already_started? false
end
```

### Terminating Processes

```elixir
# Terminate child by ID
terminate_child :stop_worker do
  supervisor input(:supervisor)
  child_id input(:worker_id)
end

# Terminate with custom timeout
terminate_child :graceful_stop do
  supervisor input(:supervisor)  
  child_id input(:worker_id)
  module Supervisor
  timeout 10_000
end

# Send exit signal to process
process_exit :kill_worker do
  process input(:worker_pid)
  reason :shutdown
  wait_for_exit? true
  timeout 5_000
end
```

## Supervisor Management {: .col-2}

### Child Management

```elixir
# Restart a child
restart_child :restart_worker do
  supervisor input(:supervisor)
  child_id input(:worker_id)
end

# Remove child specification
delete_child :cleanup_spec do
  supervisor input(:supervisor)
  child_id input(:worker_id)
end

# Count supervisor children
count_children :get_stats do
  supervisor input(:supervisor)
end
```

### DynamicSupervisor Support

```elixir
# Start under DynamicSupervisor
start_child :dynamic_worker do
  supervisor input(:dynamic_sup)
  child_spec result(:worker_spec)
  module DynamicSupervisor
end

# Terminate by PID in DynamicSupervisor
terminate_child :stop_dynamic do
  supervisor input(:dynamic_sup)
  child_id input(:worker_pid)  # Use PID for DynamicSupervisor
  module DynamicSupervisor
end
```

## Error Handling {: .col-2}

### Failure Options

```elixir
# Handle already present scenarios
start_child :maybe_start do
  supervisor input(:supervisor)
  child_spec result(:worker_spec)
  fail_on_already_present? false
  fail_on_already_started? false
end

# Handle missing children gracefully
terminate_child :maybe_stop do
  supervisor input(:supervisor)
  child_id input(:worker_id)
  fail_on_not_found? false
end
```

### Undo Behaviour

```elixir
# Control undo operations
start_link :managed_process do
  child_spec result(:worker_spec)
  terminate_on_undo? true
  termination_reason :shutdown
  termination_timeout 30_000
end

# Restart on undo
terminate_child :stoppable do
  supervisor input(:supervisor)
  child_id input(:worker_id)
  restart_on_undo? true
end
```

## Advanced Patterns {: .col-2}

### Process Dependencies

```elixir
# Wait for supervisor to be ready
start_child :dependent_worker do
  supervisor result(:supervisor_start)
  child_spec result(:worker_spec)
  wait_for [:supervisor_start]
end

# Sequential process startup
start_child :worker_a do
  supervisor input(:supervisor)
  child_spec result(:spec_a)
end

start_child :worker_b do
  supervisor input(:supervisor)
  child_spec result(:spec_b)
  wait_for [:worker_a]
end
```

## Supervisor References {: .col-2}

### Reference Types

```elixir
# PID reference
count_children :by_pid do
  supervisor input(:supervisor_pid)
end

# Registered name
count_children :by_name do
  supervisor :my_supervisor
end

# Global registration
start_child :global_sup do
  supervisor {:global, :my_global_sup}
  child_spec result(:worker_spec)
end

# Via registration
terminate_child :via_sup do
  supervisor {:via, Registry, {MyRegistry, "sup_key"}}
  child_id input(:worker_id)
end

# Remote node
restart_child :remote do
  supervisor {:node1@host, :remote_supervisor}
  child_id input(:worker_id)
end
```

## Monitoring and Introspection

### Supervisor Statistics

```elixir
# Get child counts
count_children :supervisor_stats do
  supervisor input(:supervisor)
end

# Returns: %{active: 3, specs: 5, supervisors: 1, workers: 4}
```

### Health Checks

```elixir
# Count children for health monitoring
count_children :health_check do
  supervisor input(:main_supervisor)
end

# Restart child processes
restart_child :heal_worker do
  supervisor input(:supervisor)
  child_id input(:worker_id)
end
```

## Integration Examples

### Complete Workflow

```elixir
defmodule MyAppReactor do
  use Reactor, extensions: [Reactor.Process]

  # Define child specs
  child_spec :database_spec do
    module {MyApp.Database, []}
  end
  
  child_spec :server_spec do
    module {MyApp.Server, [port: input(:port)]}
  end

  # Start supervisor first
  start_link :main_supervisor do
    child_spec {Supervisor, strategy: :one_for_one}
  end

  # Start database
  start_child :database do
    supervisor result(:main_supervisor)
    child_spec result(:database_spec)
  end

  # Start server after database
  start_child :server do
    supervisor result(:main_supervisor)
    child_spec result(:server_spec)
    wait_for [:database]
  end

  # Health monitoring
  count_children :monitor do
    supervisor result(:main_supervisor)
  end
end
```

### Error Recovery

```elixir
defmodule RecoveryReactor do
  use Reactor, extensions: [Reactor.Process]

  # Try graceful shutdown first
  terminate_child :graceful_stop do
    supervisor input(:supervisor)
    child_id input(:worker_id)
    fail_on_not_found? false
  end

  # Force kill if graceful fails
  process_exit :force_stop do
    process input(:worker_pid)
    reason :kill
    wait_for [:graceful_stop]
  end

  # Restart clean
  restart_child :fresh_start do
    supervisor input(:supervisor)
    child_id input(:worker_id)
    wait_for [:force_stop]
  end
end
```