VOOZH about

URL: https://deepwiki.com/hypervel/console/7.5-concurrency-and-mutex-management

⇱ Concurrency and Mutex Management | hypervel/console | DeepWiki


Loading...
Menu

Concurrency and Mutex Management

Purpose and Scope

This page documents the concurrency control mechanisms in the Hypervel Console scheduling system. The mutex system prevents overlapping executions of scheduled tasks and coordinates task execution across multiple servers in distributed deployments.

For information about the broader Event class and its execution lifecycle, see Event Execution and Lifecycle. For configuration methods like withoutOverlapping() and onOneServer(), which use these mutex primitives, see Execution Attributes and Configuration.

Sources: src/Scheduling/Event.php1-738 src/Contracts/EventMutex.php1-25


Mutex System Architecture

The scheduling system implements a two-tier mutex architecture to handle different concurrency scenarios:

  1. Event Mutex: Prevents the same scheduled task from running multiple times concurrently (temporal overlap)
  2. Scheduling Mutex: Ensures a task runs on only one server in a distributed environment (spatial coordination)

Mutex Architecture Diagram


Sources: src/Scheduling/Event.php36-104 src/Contracts/EventMutex.php9-25 src/Contracts/CacheAware.php7-13


EventMutex Contract

The EventMutex interface defines the contract for preventing overlapping executions of the same scheduled event. This ensures that if a task is still running when its next execution time arrives, the new execution is skipped.

Interface Definition

The contract defines three methods for managing event locks:

MethodParametersReturn TypePurpose
create()Event $eventboolAttempt to acquire a lock for the event. Returns true if lock was acquired, false if already locked.
exists()Event $eventboolCheck if a lock currently exists for the event without attempting to acquire it.
forget()Event $eventvoidRelease the lock for the event, allowing future executions.

Contract Code Structure


Sources: src/Contracts/EventMutex.php9-25


CacheAware Contract

The CacheAware interface allows mutex implementations to specify which cache store should be used for lock storage. This provides flexibility to use different cache backends (Redis, Memcached, file-based) for different events.

Interface Definition

The contract defines a single method:

MethodParametersReturn TypePurpose
useStore()string $storestaticSpecify the cache store name for lock storage. Returns $this for method chaining.

Sources: src/Contracts/CacheAware.php7-13


Preventing Overlapping Executions

The Event class integrates with the EventMutex system to prevent overlapping executions when configured with the withoutOverlapping() method.

Overlap Prevention Flow


Sources: src/Scheduling/Event.php111-124 src/Scheduling/Event.php129-133

Implementation Details

The overlap prevention logic is implemented in the run() method at the beginning of event execution:

  1. Pre-execution Check src/Scheduling/Event.php113: Before any work begins, shouldSkipDueToOverlapping() is called
  2. Conditional Lock Acquisition src/Scheduling/Event.php129-133: If $withoutOverlapping is true, attempts to create a mutex lock
  3. Skip on Lock Failure src/Scheduling/Event.php114: Returns null immediately if lock cannot be acquired
  4. Lock Cleanup src/Scheduling/Event.php732-737: The removeMutex() method releases the lock after execution completes

Sources: src/Scheduling/Event.php111-124 src/Scheduling/Event.php129-133 src/Scheduling/Event.php732-737


Mutex Name Generation

Each event requires a unique mutex name to identify its lock in the cache. The mutex name serves as the cache key for both event-level and server-level coordination.

Default Mutex Name Algorithm

The mutexName() method generates a unique identifier by hashing the event's cron expression and command:


The default implementation src/Scheduling/Event.php713-714 generates:

framework/schedule-{sha1($expression . $command)}

This ensures that:

  • Each unique schedule/command combination has a distinct lock
  • The same event scheduled at different times uses the same lock
  • Lock names are deterministic across application instances

Sources: src/Scheduling/Event.php705-715

Custom Mutex Name Resolution

The mutex name can be customized using createMutexNameUsing():

MethodParametersPurpose
createMutexNameUsing()Closure|string $mutexNameSet a custom mutex name or resolver function

Custom String Example:


Custom Resolver Example:


The implementation src/Scheduling/Event.php722-724 normalizes string values into closures, storing the resolver in the $mutexNameResolver property src/Scheduling/Event.php66

Sources: src/Scheduling/Event.php64-66 src/Scheduling/Event.php705-727


Mutex Lifecycle Management

The Event class manages the complete lifecycle of mutex locks through three key phases: acquisition, verification, and release.

Lifecycle State Diagram


Sources: src/Scheduling/Event.php111-124 src/Scheduling/Event.php156-167 src/Scheduling/Event.php213-222

Acquisition Phase

Lock acquisition occurs at the start of the run() method:


The mutex->create() call attempts to atomically set a lock key in the cache. If the key already exists (indicating an in-progress execution), the method returns false, and the event execution is skipped.

Sources: src/Scheduling/Event.php129-133 src/Contracts/EventMutex.php14

Release Phase

Lock release occurs in two scenarios, both handled by the removeMutex() method:

  1. Normal Completion src/Scheduling/Event.php219: Called in the finally block of finish()
  2. Error Recovery src/Scheduling/Event.php163: Called in the catch block if start() throws an exception

The forget() method removes the lock key from the cache, allowing future executions of the same event to proceed.

Sources: src/Scheduling/Event.php213-222 src/Scheduling/Event.php732-737 src/Contracts/EventMutex.php24


Mutex Injection and Configuration

The Event class receives its mutex implementation through constructor injection and provides methods for runtime configuration.

Constructor Injection


The $mutex parameter is required and must implement the EventMutex contract src/Scheduling/Event.php96-104 This design allows for:

  • Dependency injection of different mutex implementations
  • Testing with mock mutex objects
  • Runtime selection of mutex strategies

Sources: src/Scheduling/Event.php96-104

Runtime Mutex Replacement

The preventOverlapsUsing() method allows replacing the mutex implementation after construction:

MethodParametersReturn TypePurpose
preventOverlapsUsing()EventMutex $mutexstaticReplace the current mutex implementation

This is useful for:

  • Using different mutex implementations for different events
  • Configuring cache stores via the CacheAware interface
  • Testing with alternative mutex strategies

Sources: src/Scheduling/Event.php695-700


Cache-Based Default Implementation

While the actual implementation classes are not shown in the provided files, the architecture indicates that default mutex implementations use the cache system. Based on the high-level diagrams:

CacheEventMutex Implementation Pattern

The default CacheEventMutex implementation:

  1. Implements EventMutex contract
  2. Implements CacheAware for store selection
  3. Uses mutexName() result as cache key
  4. Leverages atomic cache operations:
    • add() for lock acquisition (atomic set-if-not-exists)
    • has() for lock checking
    • forget() for lock release

Cache Key Structure

Based on the mutexName() implementation, cache keys follow the pattern:

framework/schedule-{sha1(expression + command)}

This generates keys like:

  • framework/schedule-a3f5b1c9d2e4f6a8b0c1d3e5f7a9b1c3d5e7f9a1

The directory separator in the key name allows for organized cache key namespacing in cache stores that support hierarchical keys.

Sources: src/Scheduling/Event.php705-715


Integration with Event Execution

The mutex system integrates at multiple points in the event execution flow to ensure proper concurrency control.

Event Execution Integration Points


Critical Execution Points

Integration PointLocationPurpose
Pre-execution Checksrc/Scheduling/Event.php113Prevents execution if lock cannot be acquired
Error Recoverysrc/Scheduling/Event.php163Releases lock if exception occurs during startup
Normal Cleanupsrc/Scheduling/Event.php219-220Releases lock in finally block after callbacks complete

The finally block ensures lock cleanup occurs even if callAfterCallbacks() throws an exception, maintaining system integrity.

Sources: src/Scheduling/Event.php111-124 src/Scheduling/Event.php156-167 src/Scheduling/Event.php213-222 src/Scheduling/Event.php732-737


Single-Server Coordination

While the SchedulingMutex contract is not shown in the provided files, the system architecture indicates a second mutex tier for coordinating task execution across multiple servers. This prevents the same scheduled task from running simultaneously on different application servers in a distributed deployment.

Server Coordination Architecture


The onOneServer() configuration method (documented in Execution Attributes and Configuration) controls this behavior, using SchedulingMutex to ensure only one server in a cluster executes the task.

Sources: High-level system diagrams


Summary

The concurrency and mutex management system in Hypervel Console provides robust protection against overlapping executions and multi-server race conditions through:

ComponentPurposeKey Methods
EventMutexPrevents temporal overlap of same eventcreate(), exists(), forget()
SchedulingMutexCoordinates cross-server executionSimilar interface to EventMutex
CacheAwareConfigures cache backend selectionuseStore()
Event IntegrationManages lock lifecycle automaticallyshouldSkipDueToOverlapping(), removeMutex()
Mutex NamingGenerates deterministic lock keysmutexName(), createMutexNameUsing()

The system ensures reliable task scheduling in both single-server and distributed environments, with automatic cleanup even in error scenarios.