VOOZH about

URL: https://deepwiki.com/hypervel/console/9-error-handling-and-events

⇱ Error Handling and Events | hypervel/console | DeepWiki


Loading...
Menu

Error Handling and Events

Purpose and Scope

This document covers the error handling mechanisms and event dispatching system in the hypervel/console package. It details how exceptions are caught and handled during command execution, the ManuallyFailedException class for controlled failures, and the lifecycle events emitted during both command and scheduled task execution.

For information about command execution lifecycle, see Command System. For scheduled task execution flow, see Event Execution and Lifecycle.


Command Error Handling Architecture

Exception Handling Flow

The Command base class implements a comprehensive error handling system within its execution pipeline. The execute method wraps command execution in a try-catch-finally block that handles multiple exception types and dispatches appropriate events.

Command Exception Handling Flow


Sources: src/Command.php41-89

ManuallyFailedException

The ManuallyFailedException class is a specialized exception used to intentionally fail a command with a user-friendly error message. It extends RuntimeException and is caught specifically in the command execution flow to provide controlled failure semantics.

Class Definition:

The exception is a simple marker class that identifies intentional command failures:


Usage via fail() Method:

Commands can fail manually using the fail() method, which accepts either a string message, a Throwable exception, or null (defaults to generic message):

  • When called with a string, it wraps the message in ManuallyFailedException
  • When called with a Throwable, it re-throws that exception directly
  • When called with null, it uses the default message "Command failed manually."

Handling Behavior:

When ManuallyFailedException is caught during command execution:

  1. The error message is displayed using $this->components->error($e->getMessage())
  2. The exit code is set to Command::FAILURE (value 1)
  3. Execution continues normally without throwing further
  4. No FailToHandle event is dispatched (only applies to unexpected exceptions)

This provides a clean way for commands to signal failure conditions without exposing stack traces or triggering error event handlers.

Sources: src/ManuallyFailedException.php1-11 src/Command.php104-115 src/Command.php56-59

General Exception Handling

For all other exceptions implementing Throwable, the command execution flow follows a multi-step handling process:

1. ExitException Special Case

Swoole's ExitException receives special handling. When caught, the command extracts the exit status from the exception and returns it directly:


This allows Swoole exit semantics to propagate correctly through the command system.

2. EventDispatcher Availability Check

If no event dispatcher is bound to the command, the exception is immediately re-thrown, bypassing error rendering and event dispatching. This ensures exceptions are not silently swallowed when no error handling infrastructure exists.

3. Error Rendering

When an event dispatcher is available, the ErrorRenderer class formats and displays the exception:


The renderer receives the command's input and output interfaces to properly format the error for console display.

4. FailToHandle Event Dispatch

After rendering the error, the FailToHandle event is dispatched with both the command instance and the caught exception:


This allows event listeners to log errors, trigger alerts, or perform other error handling actions.

5. Exit Code Assignment

The exit code is set to Command::FAILURE (value 1) to indicate execution failure.

Sources: src/Command.php60-74


Command Lifecycle Events

The command execution pipeline emits four distinct events that provide observability into command execution. These events are dispatched at specific points in the execution lifecycle using the Hyperf event dispatcher.

Event Types and Timing

Event ClassDispatch LocationTimingException Available
BeforeHandleBefore handle() callPre-execution hooks, initializationNo
AfterHandleAfter successful handle()Success path onlyNo
FailToHandleWhen exception caughtError path only (except ManuallyFailedException)Yes
AfterExecutefinally blockAlways, regardless of success/failureYes (if failed)

Event Dispatch Timeline


Sources: src/Command.php47-80

BeforeHandle Event

Dispatched immediately before the command's handle() method is invoked. This event fires in all execution scenarios, providing a guaranteed pre-execution hook point.

Properties:

  • $this: The command instance being executed

Use Cases:

  • Logging command invocation
  • Recording start timestamps
  • Initializing command-specific contexts
  • Pre-execution validation

Sources: src/Command.php49

AfterHandle Event

Dispatched after the command's handle() method completes successfully without throwing exceptions. This event indicates successful execution in the normal path.

Properties:

  • $this: The command instance that completed

Use Cases:

  • Success logging
  • Execution time calculation (paired with BeforeHandle)
  • Success metrics collection
  • Post-execution cleanup for successful runs

Sources: src/Command.php55

FailToHandle Event

Dispatched when any exception (except ManuallyFailedException and ExitException) is caught during command execution. This event provides both the command context and the exception details.

Properties:

  • $this: The command instance that failed
  • $exception: The Throwable that was caught

Use Cases:

  • Error logging and tracking
  • Exception reporting to error tracking services
  • Failure alerts and notifications
  • Error rate monitoring

Important: This event is only dispatched when an event dispatcher is available. If no dispatcher exists, the exception is re-thrown.

Sources: src/Command.php74

AfterExecute Event

Dispatched in the finally block of the execution flow, guaranteeing it fires regardless of success, failure, or ManuallyFailedException. This is the only event that always executes.

Properties:

  • $this: The command instance
  • $exception: The Throwable if one occurred, otherwise null

Use Cases:

  • Resource cleanup
  • Execution time tracking (paired with BeforeHandle)
  • Audit logging
  • Always-execute hooks
  • Metric finalization

Key Characteristic: This event receives the exception parameter even in the success case (as null), allowing listeners to distinguish between success and failure paths.

Sources: src/Command.php76

Conditional Event Dispatching

All event dispatching in the command system uses the null-safe operator to ensure commands can function without event infrastructure:


This pattern is applied consistently across all four lifecycle events, allowing commands to operate in minimal environments.

Sources: src/Command.php49 src/Command.php55 src/Command.php74 src/Command.php76


Scheduled Task Events

The scheduling system emits three lifecycle events for each scheduled task execution, providing observability into task status. These events are dispatched by the Event class during task execution and follow a similar pattern to command lifecycle events.

Scheduled Task Event Classes


Sources: src/Events/ScheduledTaskStarting.php1-19 src/Events/ScheduledTaskFailed.php1-20

ScheduledTaskStarting

Dispatched immediately before a scheduled event begins execution. This event fires after all eligibility checks pass (isDue, filtersPass, mutex checks) but before the actual execution starts.

Properties:

  • task (Event): The scheduled event instance about to execute

Constructor:


Use Cases:

  • Task initiation logging
  • Recording start timestamps for task execution time tracking
  • Initializing monitoring contexts per task
  • Incrementing task execution counters
  • Pre-execution notifications

Sources: src/Events/ScheduledTaskStarting.php9-18

ScheduledTaskFinished

Dispatched after a scheduled event completes successfully without throwing exceptions. This event indicates the task ran to completion in the normal path.

Properties:

  • task (Event): The scheduled event instance that completed successfully

Use Cases:

  • Success logging for scheduled tasks
  • Execution time calculation (paired with ScheduledTaskStarting)
  • Success metrics and monitoring
  • Post-execution cleanup for successful tasks
  • Success notifications

Note: The implementation file for this class was not provided in the source listing, but it is referenced in system documentation and follows the same pattern as ScheduledTaskStarting.

ScheduledTaskFailed

Dispatched when a scheduled event throws an exception during execution. This event provides both the task context and the exception details for comprehensive error handling.

Properties:

  • task (Event): The scheduled event instance that failed
  • exception (Throwable): The exception that caused the failure

Constructor:


Use Cases:

  • Task failure logging and tracking
  • Exception reporting to error tracking services
  • Failure alerts and notifications (email, Slack, etc.)
  • Retry decision logic
  • Task failure rate monitoring
  • Debugging and troubleshooting

Sources: src/Events/ScheduledTaskFailed.php10-19


Scheduled Task Event Flow

The scheduled task execution integrates event dispatching at key lifecycle points. Events are dispatched through the application's event dispatcher as tasks progress through their execution pipeline.

Task Execution State Diagram


Event Dispatch Integration Points

The scheduled task events integrate with the broader execution pipeline:

  1. Pre-Execution Gate: After passing isDue, filtersPass, and mutex checks
  2. Starting Event: Dispatched before before-callbacks
  3. Execution: The actual task runs (command, callback, or job)
  4. Success/Failure Branching: Based on exception occurrence
  5. Finished/Failed Event: Dispatched before after-callbacks
  6. Cleanup: After-callbacks run, mutex released

This flow ensures events are dispatched at the appropriate times for monitoring while maintaining proper resource cleanup even in failure scenarios.

Sources: Based on high-level architecture diagrams and event class structure


Exit Code Management

The error handling system carefully manages command exit codes to communicate execution status to callers and external systems (such as cron or process supervisors).

Exit Code Values

ScenarioExit CodeConstantSet Location
Successful execution0 or custom valueCommand::SUCCESShandle() return value
Manual failure via fail()1Command::FAILUREManuallyFailedException handler
Exception thrown1Command::FAILUREGeneral exception handler
ExitException caughtException statusN/AExitException handler
Out of range (0-255)255Command::INVALIDExit validation

Exit Code Validation

The final exit code is validated to ensure it falls within the POSIX-compliant range (0-255):


This validation catches programmer errors where invalid exit codes might be returned from handle() methods.

Exit Code Setting Points


Sources: src/Command.php52-54 src/Command.php59 src/Command.php62 src/Command.php72 src/Command.php88


ErrorRenderer System

The ErrorRenderer class formats and displays exception details to the console output when unexpected exceptions occur during command execution. This system is separate from ManuallyFailedException handling, which displays simple error messages without stack traces.

Error Rendering Integration


Instantiation and Usage

The error renderer is instantiated with the command's input and output interfaces:


This ensures the renderer has access to:

  • Console input parameters for context
  • Styled output capabilities for formatting
  • Terminal dimensions for proper wrapping

Execution Context

The error renderer is invoked:

  • After the exception is caught
  • Before the FailToHandle event is dispatched
  • Before the finally block executes
  • Only when an event dispatcher is available

This positioning ensures users see formatted error output before event handlers are notified of the failure.

Sources: src/Command.php69-70


Integration with Event Dispatcher

The error handling and event system relies on the Hyperf event dispatcher for all event broadcasting. Commands maintain an optional reference to the event dispatcher and use null-safe dispatching throughout.

Event Dispatcher Architecture


Conditional Dispatching Pattern

All event dispatching uses the null-safe operator (?->) to allow commands to function without event infrastructure:


This pattern ensures:

  • Commands work in minimal environments without event systems
  • No null pointer exceptions occur when dispatcher is unavailable
  • Optional observability without breaking core functionality

Error Handling Without Dispatcher

When no event dispatcher is bound and an exception occurs:

  1. The exception is immediately re-thrown without rendering
  2. No FailToHandle event is dispatched
  3. No AfterExecute event is dispatched
  4. Exception propagates to the caller

This behavior prevents silent exception swallowing when no error handling infrastructure exists.

Sources: src/Command.php49 src/Command.php55 src/Command.php65-66 src/Command.php74 src/Command.php76


Observability Patterns

The error handling and event system enables several observability patterns through strategic event listener registration.

Pattern 1: Execution Duration Tracking

Track command execution time by pairing BeforeHandle and AfterExecute events:

Listener receives BeforeHandle → Record start timestamp
Listener receives AfterExecute → Calculate duration = now - start
 → Log execution time with command name

Advantage: AfterExecute fires in all scenarios (success, failure, manual failure), ensuring complete duration data.

Pattern 2: Error Rate Monitoring

Monitor command and task failure rates by counting FailToHandle and ScheduledTaskFailed events:

Listener receives FailToHandle → Increment command_failures counter
 → Tag with command name
Listener receives ScheduledTaskFailed → Increment task_failures counter
 → Tag with task expression

Metric Export: Push counters to monitoring systems (Prometheus, StatsD, CloudWatch)

Pattern 3: Comprehensive Audit Logging

Create audit trails using the complete event lifecycle:

For Commands:

BeforeHandle → Log: "Command {name} started by {user}"
AfterHandle → Log: "Command {name} completed successfully in {duration}s"
FailToHandle → Log: "Command {name} failed: {exception.message}"
AfterExecute → Log: "Command {name} finished with exit code {exitCode}"

For Scheduled Tasks:

ScheduledTaskStarting → Log: "Task {expression} {command} starting"
ScheduledTaskFinished → Log: "Task {expression} completed successfully"
ScheduledTaskFailed → Log: "Task {expression} failed: {exception.message}"

Pattern 4: Exception Aggregation

Collect exceptions for analysis and alerting:

Listener receives FailToHandle:
 → Extract exception class, message, stack trace
 → Send to error tracking service (Sentry, Rollbar)
 → Check if critical exception type → Trigger alert

Listener receives ScheduledTaskFailed:
 → Extract task details (expression, command)
 → Send to error tracking with task context
 → Check failure count threshold → Trigger alert

Pattern 5: Success Metrics

Track successful operations for SLA monitoring:

Listener receives AfterHandle → Increment command_success counter
Listener receives ScheduledTaskFinished → Increment task_success counter

Calculate: success_rate = successes / (successes + failures)

Pattern 6: Before/After Hooks

Implement cross-cutting concerns using event listeners:

BeforeHandle listener:
 → Start database transaction
 → Initialize performance profiler
 → Set request context

AfterExecute listener:
 → Commit/rollback transaction based on exit code
 → Flush profiler data
 → Clear request context

Event Correlation

Events can be correlated using command instance identity or scheduled task properties:

BeforeHandle event contains command instance $cmd
AfterExecute event contains same command instance $cmd
→ Use object identity or command name for correlation

ScheduledTaskStarting contains Event $task
ScheduledTaskFinished contains same Event $task
→ Use task instance or task identifier for correlation

Summary

The error handling and events system provides comprehensive observability and control over command and scheduled task execution:

Error Handling Features

  • Three-Tier Exception Handling: Specialized handling for ManuallyFailedException, ExitException, and general Throwable
  • Graceful Degradation: Commands function without event infrastructure via null-safe dispatching
  • Formatted Error Output: ErrorRenderer provides developer-friendly exception display
  • Exit Code Standards: POSIX-compliant exit codes (0-255) with validation

Event System Features

  • Seven Lifecycle Events: Four command events (BeforeHandle, AfterHandle, FailToHandle, AfterExecute) and three scheduled task events (ScheduledTaskStarting, ScheduledTaskFinished, ScheduledTaskFailed)
  • Consistent Event Pattern: All events contain relevant context (command/task instance, exception when applicable)
  • Always-Execute Guarantee: AfterExecute fires in finally block for cleanup and metrics
  • Conditional Dispatching: Null-safe operator allows optional event infrastructure

Observability Capabilities

  • Execution Tracking: Duration measurement, invocation counting
  • Error Monitoring: Exception aggregation, failure rate tracking
  • Audit Logging: Complete execution history with context
  • Performance Profiling: Before/after hooks for instrumentation

This architecture enables robust error handling in development while providing the hooks necessary for comprehensive monitoring, logging, and alerting in production environments.

Sources: src/Command.php41-126 src/ManuallyFailedException.php1-11 src/Events/ScheduledTaskStarting.php1-19 src/Events/ScheduledTaskFailed.php1-20

Refresh this wiki

On this page