spatie/async
Run PHP tasks in parallel with a simple Pool API built on PCNTL. Add closures, handle results via then/catch, and wait for completion. Ideal for speeding up batch jobs, CPU-heavy work, and IO-bound processing with multiple processes.
Installation:
composer require spatie/async
Ensure your server has pcntl extension enabled (check php -m | grep pcntl).
First Use Case: Run a simple parallel task:
use Spatie\Async\Async;
Async::run(function () {
// Long-running task (e.g., processing a large file)
file_put_contents('output.txt', 'Hello from async!');
});
Where to Look First:
Basic Parallel Execution:
Async::parallel([
fn() => processUserData($users[0]),
fn() => processUserData($users[1]),
fn() => processUserData($users[2]),
]);
Chaining Async Tasks:
$result = Async::run(function () {
$data = fetchRemoteData();
return Async::run(fn() => transformData($data));
})->wait();
Error Handling:
Async::run(function () {
try {
riskyOperation();
} catch (\Throwable $e) {
reportError($e);
}
})->catch(fn($e) => logger()->error($e->getMessage()));
wait() or catch() to handle failures gracefully.Integration with Laravel Jobs:
Async::run(function () {
dispatch(new ProcessLargeFileJob($file));
});
Process Limits:
config(['async.max_processes' => 4]); // Limit concurrent processes.
Timeouts:
Async::run(fn() => slowTask(), timeout: 30)->wait();
Shared Memory:
Async::run(function () {
$shared = new \Spatie\Async\SharedMemory\SharedMemory('key');
$shared->set('value');
});
PCNTL Dependency:
pcntl is not enabled by default on shared hosting (e.g., Heroku, shared Linux).Async::fallback() for non-pcntl environments:
Async::fallback(function () {
// Fallback to synchronous execution.
});
Memory Leaks:
Async::run(fn() => ..., memory_limit: '128M') to enforce limits.Race Conditions:
SharedMemory for synchronization.Debugging:
getmypid()) to track async tasks:
Async::run(function () {
logger()->info("Running PID: " . getmypid());
});
Laravel Artisan Commands:
Async::run(function () {
Artisan::call('queue:work');
});
Dynamic Process Count:
$processes = ceil(count($items) / config('async.max_processes'));
Async::parallel(array_chunk($items, $processes), fn($chunk) => processChunk($chunk));
Extension Points:
Spatie\Async\Async to add custom logging or metrics.SharedMemory for complex IPC (e.g., Redis-backed shared state).Testing:
Async in tests using Async::shouldReceive('run')->once().Async::run(fn() => sleep(10), timeout: 1) to verify failure paths.Performance:
Async::parallel() vs. Laravel’s dispatchSync() for CPU-bound tasks.How can I help you explore Laravel packages today?