Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Easy Async Laravel Package

eonx-com/easy-async

EasyAsync is a Laravel package that simplifies running asynchronous work, letting you dispatch jobs and process tasks in the background without blocking requests. It offers a clean API for queue-based execution so your app stays fast and responsive.

View on GitHub
Deep Wiki
Context7

Getting Started

eonx-com/easy-async is a thin abstraction over running external processes (shell commands, artisan invocations, binaries) without blocking the calling PHP process. Treat it as plumbing, not a framework: the value is in not hand-rolling proc_open, output buffering, and exit-code checks every time you need to shell out.

Because the package is at 0 stars, 0 dependents, and "docs" maturity, do not adopt it blind. Budget 30–45 minutes of source reading before wiring it into anything that matters.

1. Install and confirm what you actually got

composer require eonx-com/easy-async

Then immediately check:

  • composer.json in the package — look for extra.laravel.providers / aliases. If there's no auto-discovery, you must register the service provider manually in bootstrap/providers.php (Laravel 11+) or config/app.php.
  • The src/ tree. With a low-maturity package, the source is the documentation. Look for the main factory/manager class, the process wrapper, and any Contract/Interface directory.
  • tests/ if present — the test suite is the most reliable spec for the API surface.

2. First read: the public entry point

Find the class you're meant to instantiate (commonly a manager, factory, or pool). Note whether it is bound in the container as a singleton — that determines whether state (like a pool of running processes) leaks between calls in a long-lived worker.

3. First use case

The canonical day-one use case is moving a slow blocking call off the request path. Example: a controller currently does exec('pdftk ...') and takes 4 seconds. Replace it with:

// Illustrative — verify class/method names against src/
$process = app(ProcessManager::class)->create('pdftk', [$input, 'output', $path]);
$process->run();          // async start
// ... respond to the user, or hand the handle to a queued job

If the package's abstraction does not save you at least the proc_open + stream-select loop, it is not earning its dependency. That's the bar to test against.


Implementation Patterns

Pattern 1: Fire-and-forget for side-effect commands

Best for operations where the caller doesn't need the result — cache warming, thumbnail generation, log rotation, webhook delivery to a slow endpoint. Start the process, register a completion callback (or simply don't wait), and let the request return.

The trade-off: if the PHP process exits before the child finishes, orphaned processes accumulate. Prefer this inside a queue job rather than a web request, so the job's lifetime bounds the child's.

Pattern 2: Bounded pool for fan-out

The highest-leverage usage. If you have 200 files to transcode and each takes 2s, sequential is 400s. A pool with concurrency 4 gets you to ~100s. Typical shape:

$pool = $manager->pool(concurrency: 4);

foreach ($files as $file) {
    $pool->add($manager->create('ffmpeg', ['-i', $file, $target($file)]));
}

$pool->wait(); // blocks, but processes run concurrently

This is where the package genuinely pays for itself — hand-writing a correct pool with output draining and exit-code collection is fiddly and easy to get subtly wrong (deadlocks from full pipe buffers are the classic failure).

Pattern 3: Process-per-job, one job per process

An alternative to a pool that composes better with Laravel's queue:

// Job
public function handle(ProcessManager $manager): void
{
    $result = $manager->create($this->command, $this->args)->runAndWait();

    if (! $result->isSuccessful()) {
        throw new RuntimeException($result->getErrorOutput());
    }
}

Dispatch N jobs, let queue:work provide the concurrency, and you inherit retries, backoff, failed_jobs, Horizon metrics, and timeouts for free. For most Laravel apps this is the better default than in-request pooling — the pool only wins when N is large enough that per-job queue overhead dominates, or when you need results synchronously.

Pattern 4: Output handling for progress and diagnostics

Capture stdout/stderr separately and log stderr on non-zero exit. Route child output through your existing logger rather than letting it hit the terminal — under a supervisor, unattended output either goes nowhere or floods logs. If the package exposes incremental callbacks (per-line or per-chunk), use them for heartbeats so a hung child is distinguishable from a slow one.

Pattern 5: Wrap in an application-level service

Don't let the package's API leak into controllers or jobs. Put a small adapter in app/Support/ that exposes domain methods (generateThumbnail(), exportCsv()) and takes the package as a constructor dependency. When the package stalls at 0 stars and you swap it for Symfony Process or Illuminate\Process, you change one file.


Gotchas and Tips

Verify before you commit. Zero dependents means no ecosystem has battle-tested this. Check the last commit date, whether composer.json pins php/laravel/framework constraints that match your stack, and whether CI is green. An unmaintained async-process wrapper is a liability, not an asset — the failure modes are process leaks and hangs, which are expensive in production.

Argument escaping is your problem, not the package's. Confirm whether the API takes an array of args (safe, no shell) or a single command string (shell, injection risk). Never interpolate user input into a command string. If only the string form exists, use escapeshellarg() yourself.

Pipe buffer deadlocks. If you start a process and don't read its output, a chatty child fills the OS pipe buffer (~64KB) and blocks forever. Any abstraction that offers a "start now, read later" API must drain output continuously. Test with a command that emits >100KB, and with the disableOutput() equivalent if available.

Timeouts are not optional. Every external process needs one. Confirm the default timeout and set it explicitly per call. A command with no timeout that hangs will occupy a queue worker until your supervisor gives up.

Zombie processes and orphaned children. If your PHP process dies mid-flight, does the child die too? Look for signal handling, proc_terminate, or a destructor. In long-lived workers (queue:work, Octane), a manager bound as a singleton can retain handles across jobs — check for a reset/flush method and call it, or resolve the manager as a fresh instance per job.

Exit code 0 is not "success" for every tool. Some binaries return 0 with warnings on stderr. Decide per-integration whether to treat non-empty stderr as failure, and assert on expected output artifacts rather than trusting the code alone.

Environment differs between CLI and FPM. PATH, locale, and the working directory will differ from what you get in a shell. Use absolute binary paths in config, and pass an explicit cwd if the tool writes relative files.

Testing. You want a fake/sync mode — look for an interface you can bind to a stub, or a config toggle that runs processes synchronously. Assert on the process's command and args rather than executing the real binary. If neither exists, wrap the manager in your own interface (Pattern 5) so tests never touch the real thing.

Extension points to inspect. Common candidates: a custom process factory, an output formatter/parser, an event dispatched before/after execution, and a config file (config/easy-async.php) for defaults like timeout and concurrency. If none of these exist, the abstraction is shallow and you may get more mileage from Illuminate\Process (Laravel 10+) or Symfony\Component\Process\ProcessPool directly, both of which are maintained and documented.

Decision heuristic. Use this package only if its pool implementation is correct and saves you real code. Otherwise, Illuminate\Process for one-off commands plus queue jobs for concurrency covers 90% of Laravel async-process needs with zero third-party risk.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
friendlylabs/surveyr
mg-techlegend/laravel-notify-africa
islamabdurahman/laravel-sms-service
dmhendricks/b2-sdk-php
aplicativa/laravel-admin
ezavalishin/vkma
jackardios/laravel-json-api-paginate
viral/laravel-adminpanel
dieppk/log-viewer
daimakuai-ext/helpers
codexshaper/php-blade-view
abraxas81/charts
adamlien/laravel-cas
quimgc/tasks
sistem-atc/bank-sdk
core45/laravel-cookieconsent
projectsend/community-modules
ovac/laravel-hubtel-payment
capimail/capimail-php
shiroamada/green-api-laravel-notification