Action System Architecture
Architecture of the Action Registry and Execution System
⚡ Action System Architecture
The Action System provides a decoupled, resilient way to execute operations across module boundaries.
It implements the Command Pattern to encapsulate requests as objects, enabling logging, queuing, and undo/redo capabilities.
🎯 Design Goals
- Decoupling: Sender does not need to know the receiver's implementation.
- Resilience: Circuit Breaker pattern prevents cascading failures.
- Observability: Full execution tracing and event emission.
- Discovery: Auto-discovery of actions via
@PublicAction.
🏗️ High-Level Architecture
graph LR
Client[Client Code] --> Handler[ActionHandlerService]
Handler --> Registry[ActionRegistryService]
Handler --> Circuit[CircuitBreakerService]
Registry --> Metadata[Action Metadata]
Handler --> Execute[ExecutableAction]
Execute --> Event[EventBus]
Core Components
1. ActionHandlerService
The invoker. Responsible for executing actions, managing state, and handling errors.
- Features: Single/Batch execution, transaction support, event emission.
2. ActionRegistryService
The central repository. Stores metadata for all available actions.
- Features: O(1) lookup, signal-based state, dynamic registration.
3. CircuitBreakerService
The safety valve. Monitors failures and "opens" the circuit to prevent system overload.
- States: Closed (Normal), Open (Failing), Half-Open (Recovering).
4. ActionDiscoveryService
Scans modules for actions decorated with @PublicAction and registers them.
🧩 Implementation Patterns
Command Interface
All actions must implement ExecutableAction.
interface ExecutableAction<T> {
execute(params: ActionParams, context: ActionContext): Observable<T>;
validate?(params: ActionParams): Observable<boolean>;
cleanup?(): void;
}
Decorator: @PublicAction
Marks a class as a discoverable action.
@PublicAction({
id: 'users:create',
name: 'Create User',
description: 'Creates a new user',
permissions: ['users:create'],
tags: ['users', 'crud']
})
export class CreateUserAction implements ExecutableAction<User> { ... }
🔄 Execution Flow
- Request: Client calls
ActionHandlerService.execute('action-id', params). - Lookup: Handler checks
ActionRegistryServicefor metadata. - Guard: Checks
CircuitBreakerService. If open, fail fast. - Validation: Calls action's
validate()method. - Execution: Calls
execute(). - Result:
- Success: Update stats, emit
ActionExecutedEvent, return result. - Failure: Update stats, emit error, trigger Circuit Breaker.
- Success: Update stats, emit
🛡️ Resilience & Circuit Breaker
To prevent one failing module from bringing down the system, we use a Circuit Breaker.
- Threshold: 5 failures (configurable).
- Timeout: 30 seconds reset timeout.
- Fallback: Auto-rejects calls when open to allow service recovery.
📊 State Management
The system uses Angular Signals for reactive state management:
actionsMap: Map of registered actions.executionHistory: Log of recent executions.circuitState: Status of each circuit breaker.
Status: ✅ Production Architecture Last Updated: December 3, 2025