VOOZH about

URL: https://deepwiki.com/hypervel/event/3-asynchronous-event-processing

⇱ Asynchronous Event Processing | hypervel/event | DeepWiki


Loading...
Menu

Asynchronous Event Processing

Purpose and Scope

This document provides an overview of asynchronous event processing in the hypervel/event package. It explains the queue integration architecture, the components that enable listeners to execute asynchronously, and when to use async processing for event handlers.

For detailed information about configuring closures for queueing, see QueuedClosure. For the internal job wrapper mechanics, see CallQueuedListener. For practical implementation guidance, see Configuring Queued Events.


Queue Integration Architecture

The hypervel/event package provides asynchronous event processing through integration with hypervel/queue, which is an optional dependency specified in composer.json42

Async processing allows event listeners to execute in the background through a queue system, rather than blocking the current request. This is critical for time-consuming operations like sending emails, processing uploads, or calling external APIs.

Core Components

Three primary components enable async event processing:

ComponentFilePurpose
EventDispatchersrc/EventDispatcher.phpDetects when listeners should be queued and dispatches them to the queue system
QueuedClosuresrc/QueuedClosure.phpWraps closure-based listeners for serialization and queueing
CallQueuedListenersrc/CallQueuedListener.phpJob wrapper that executes queued listeners when workers process the queue

Async Event Processing Flow


Sources: src/EventDispatcher.php273-522 src/CallQueuedListener.php1-140


Queue Detection Mechanism

The EventDispatcher detects queued listeners through the ShouldQueue interface. When preparing a class-based listener, it checks whether the listener implements this interface.

Detection Process

The detection occurs in src/EventDispatcher.php395-408:


The method src/EventDispatcher.php397-408 handles both string class names and object instances:

  • String class: Uses ReflectionClass to check interface implementation
  • Object instance: Uses instanceof operator
  • Exception handling: Returns false if reflection fails

When a listener is determined to be queueable, the dispatcher creates a queued handler callable via src/EventDispatcher.php413-424

Sources: src/EventDispatcher.php395-424


Queue Dispatch Flow

Once a listener is identified as queueable, the EventDispatcher orchestrates the queueing process through several steps.

Queueing Process

Queue Handler Execution Flow


Sources: src/EventDispatcher.php413-522

Step-by-Step Breakdown

1. Event Argument Cloning

src/EventDispatcher.php416-418 clones event objects to prevent modifications during async execution:


2. Conditional Queueing Check

src/EventDispatcher.php445-454 allows listeners to opt out of queueing at runtime via a shouldQueue() method.

3. Job Creation

src/EventDispatcher.php483-492 instantiates the listener and wraps it in a CallQueuedListener job:

StepActionLocation
InstantiateCreate listener without constructorsrc/EventDispatcher.php485
WrapCreate CallQueuedListener with class, method, argssrc/EventDispatcher.php490
PropagateCopy listener properties to jobsrc/EventDispatcher.php488-491

4. Option Propagation

src/EventDispatcher.php497-522 copies configuration from the listener to the job wrapper:

Propagated Properties

PropertySourceDescription
afterCommitShouldQueueAfterCommit or $listener->afterCommitWhether to wait for DB commit
backoffbackoff() method or $listener->backoffRetry delay calculation
maxExceptions$listener->maxExceptionsMax uncaught exceptions allowed
retryUntilretryUntil() methodTimestamp deadline for retries
shouldBeEncryptedShouldBeEncrypted interfaceEncrypt job payload
timeout$listener->timeoutExecution timeout in seconds
failOnTimeout$listener->failOnTimeoutFail vs release on timeout
tries$listener->triesMaximum attempts
middlewaremiddleware() method or $listener->middlewareJob middleware pipeline

5. Queue Resolution and Push

src/EventDispatcher.php463-478 determines the target queue and dispatches:

  • Connection: Via viaConnection() method or $listener->connection property
  • Queue name: Via viaQueue() method or $listener->queue property
  • Delay: Via withDelay() method or $listener->delay property

Sources: src/EventDispatcher.php459-522


QueuedClosure vs CallQueuedListener

The system provides two pathways for async execution, depending on the listener type.

Component Comparison

AspectQueuedClosureCallQueuedListener
PurposeWraps closure listeners for queueingWraps class-based listeners for queueing
Filesrc/QueuedClosure.phpsrc/CallQueuedListener.php
SerializationUses SerializableClosureStores class name and serializes event
ConfigurationFluent API (connection, delay, catch)Properties copied from listener
RegistrationUsed with listen() methodCreated internally by EventDispatcher

QueuedClosure Pathway

Closure Queueing Architecture


src/QueuedClosure.php79-90 shows the resolution process:

  1. Creates a wrapper closure that dispatches a CallQueuedListener
  2. Wraps the original closure in SerializableClosure for serialization
  3. Stores catch callbacks as serializable closures
  4. Applies queue configuration (connection, queue, delay)
  5. The CallQueuedListener targets InvokeQueuedClosure::class with method handle

Sources: src/QueuedClosure.php1-91 src/EventDispatcher.php129-139

CallQueuedListener Pathway

Class-Based Listener Queueing


src/CallQueuedListener.php70-80 shows the execution process:

  1. Worker deserializes the CallQueuedListener job
  2. handle() method retrieves listener from DI container
  3. Sets the job instance on the listener (if it uses InteractsWithQueue)
  4. Executes the listener method with event arguments

Sources: src/CallQueuedListener.php1-140 src/EventDispatcher.php413-492


Serialization and Queue Storage

Async processing requires serializing event data and listener information for storage in the queue backend.

Serialization Strategy by Type

Listener TypeSerialization MethodStorage Format
ClosureSerializableClosure from LaravelSerialized closure with context
Class-basedClass name + method + arguments['class' => string, 'method' => string, 'data' => array]
Event objectPHP serialization via queueSerialized event properties

SerializableClosure Integration

The package depends on laravel/serializable-closure (composer.json39) to enable closure queueing. This library:

  • Captures closure scope and bound variables
  • Serializes the closure's PHP code representation
  • Reconstructs the closure on deserialization
  • Handles closure context and binding

src/QueuedClosure.php83 wraps closures in SerializableClosure:


Data Preparation on Execution

src/CallQueuedListener.php115-120 handles deserialization:

  • Checks if data is string (serialized format)
  • Unserializes if necessary
  • The defensive coding accounts for queue serialization variations

Sources: src/QueuedClosure.php79-90 src/CallQueuedListener.php115-120 composer.json39


When to Use Asynchronous Processing

Recommended Use Cases

ScenarioReasonExample
External API callsAvoid blocking on network latencySending webhooks, syncing with third-party services
Email/notificationsTime-consuming SMTP operationsOrder confirmations, password resets
File processingCPU-intensive operationsImage resizing, PDF generation
Data aggregationComplex queries or calculationsReport generation, analytics
Batch operationsMultiple operations per eventSyncing data across multiple systems

Trade-offs and Considerations

Advantages:

  • Response time: Request returns immediately without waiting for listeners
  • Failure isolation: Listener failures don't break the request
  • Retry capability: Automatic retry on transient failures
  • Resource management: Offload work to queue workers

Disadvantages:

  • Eventual consistency: Listeners execute after the event returns
  • Debugging complexity: Failures occur in worker context, not request context
  • Infrastructure requirement: Requires queue backend (Redis, database, etc.)
  • Serialization overhead: Objects must be serializable

Performance Characteristics

MetricSynchronousAsynchronous
Response timeSum of all listener execution timesMinimal (queue dispatch overhead)
Guaranteed executionYes, in request scopeNo, depends on worker availability
Failure handlingImmediate (can halt request)Deferred (via failed() methods)
Order guaranteesStrict by priorityQueue-dependent ordering

Sources: src/EventDispatcher.php273-282 src/EventDispatcher.php413-424


Integration with Transaction Management

Queued listeners can coordinate with database transactions using the ShouldQueueAfterCommit interface or afterCommit property.

After-Commit Queueing

src/EventDispatcher.php502-506 propagates the after-commit configuration:


This ensures the job is only dispatched to the queue after the current database transaction commits successfully. If the transaction rolls back, the job is discarded.

For detailed information on transaction-aware event processing, see Transaction-Aware Events.

Sources: src/EventDispatcher.php502-506


Queue Configuration Options

Listeners can specify queue behavior through properties and methods. The EventDispatcher queries these during job creation.

Configuration Properties

PropertyTypeMethod AlternativePurpose
connection?stringviaConnection()Queue connection name
queue?stringviaQueue()Specific queue name
delayint|DateInterval|DateTimeInterface|nullwithDelay()Delay before processing
tries?intMaximum attempts
timeout?intExecution timeout in seconds
backoff?intbackoff() methodSeconds between retries
maxExceptions?intMax uncaught exceptions
retryUntilDateInterval|DateTimeInterface|int|nullretryUntil() methodDeadline timestamp
failOnTimeoutboolFail vs release on timeout
middlewarearraymiddleware() methodJob middleware
afterCommit?boolQueue after DB commit

Method Resolution Priority

The EventDispatcher prefers methods over properties:

  1. Check for method: e.g., viaConnection(), withDelay()
  2. Check for property: e.g., $listener->connection, $listener->delay
  3. Default to null: If neither exists

This pattern is visible in src/EventDispatcher.php463-478

For practical configuration examples, see Configuring Queued Events.

Sources: src/EventDispatcher.php463-522 src/CallQueuedListener.php21-54


Error Handling in Queued Listeners

Queued listeners support error handling through the failed() method, which executes when a job permanently fails.

Failed Method Invocation

src/CallQueuedListener.php99-110 implements the failure callback:


The failed() method receives:

  • Original event arguments (unpacked from $this->data)
  • The exception that caused the failure (appended as last parameter)

For closure-based listeners, error handling is configured via catch callbacks. See QueuedClosure for details.

Sources: src/CallQueuedListener.php99-110


Architecture Summary

Complete Async Processing Architecture


Sources: src/EventDispatcher.php1-618 src/QueuedClosure.php1-91 src/CallQueuedListener.php1-140

Refresh this wiki

On this page