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

Long Running Laravel Package

long-running/long-running

LongRunning is a Laravel package for managing long-running tasks and processes. It provides helpers for execution limits, process signals, and graceful shutdowns, helping background jobs and commands run reliably without being cut off.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by treating this as a monorepo of split packages, not a single library. Before installing anything, open the repository root composer.json and check for replace, provide, and repositories entries. Many monorepos publish long-running/* subpackages separately, so your actual dependency may be something like long-running/core, long-running/worker, or long-running/signals. Read each subpackage’s README.md and composer.json before choosing one.

Minimal install:

composer require long-running/long-running
php artisan vendor:publish --tag=long-running-config   # confirm tag in README
php artisan list | grep long                            # see registered commands

If the package’s service provider is not auto-discovered, register it in bootstrap/providers.php (Laravel 11+) or config/app.php. Then look first at:

  1. The root README.md and any docs/ directory.
  2. packages/ or src/ — this reveals the real class names and namespaces.
  3. The package’s config/*.php — almost all long-running behavior is tuning (timeouts, sleep intervals, signal handling).
  4. The composer.json require block — this tells you whether it expects ext-pcntl, ext-posix, or a specific Laravel version.

The first practical use case is wrapping an existing artisan command in a resilient loop. Take a command that currently processes one batch and exits, and give it a supervised run loop with graceful shutdown:

protected $signature = 'events:consume {--max-iterations=0}';

public function handle(): int
{
    $this->trap([SIGTERM, SIGINT], fn () => $this->stop());

    $iterations = 0;
    while ($this->running) {
        $this->processBatch();

        if ($this->option('max-iterations') && ++$iterations >= (int) $this->option('max-iterations')) {
            break;
        }

        sleep((int) config('long-running.sleep', 1));
    }

    return self::SUCCESS;
}

Laravel’s $this->trap() is available in recent versions; if the package predates it, check whether it ships its own signal registrar. Run one iteration with --max-iterations=1 before trusting it.

Implementation Patterns

1. Loop-and-supervise, don’t daemonize yourself. Let Supervisor, systemd, Kubernetes, or Horizon own the process lifecycle. The package should provide the loop, heartbeat, and signal handling; your deployment tool restarts the process. A typical Supervisor block:

[program:events-consumer]
command=php /var/www/artisan events:consume
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stopwaitsecs=30
numprocs=2

Set stopwaitsecs greater than the package’s graceful-shutdown timeout, otherwise Supervisor will SIGKILL mid-batch.

2. Use it behind queue workers, not instead of them. For jobs, the pattern that pays off is a custom worker loop that calls $this->runNextJob() inside a controlled cycle and emits heartbeats. Keep php artisan queue:work for normal traffic and use long-running only for workloads that need persistent in-memory state, high job throughput, or custom scheduling. If you already run Horizon, do not double-manage workers; Horizon already handles restarts, balancing, and timeouts.

3. Checkpoint and make batches idempotent. Long-running processes fail at arbitrary points. Persist a cursor (last_processed_id, last_checkpoint_at) and make processBatch() safe to replay. A crash should resume, not duplicate. Use Cache::lock() or withoutOverlapping() semantics if multiple processes read the same cursor.

4. Heartbeats and health checks. Write a timestamp to the cache each iteration and expose it:

Cache::put('long-running:events-consumer:heartbeat', now(), 300);

Alert if the heartbeat is older than two or three intervals. This catches silent hangs that process supervision alone misses.

5. Hygiene every N iterations. Long-running PHP accumulates state. Reconnect and clear periodically:

if ($iterations % 100 === 0) {
    DB::purge();
    DB::reconnect();
    gc_collect_cycles();
    $this->laravel->forgetScopedInstances();
}

Also disable query logging (DB::disableQueryLog()) and avoid Model::preventLazyLoading() overhead unless you need it.

6. Bound iterations in tests. Never write a test that relies on while (true). Expose --once or --max-iterations, call Artisan::call() with that flag, and assert side effects. Use Carbon::setTestNow() for time-based logic and a fake cache for heartbeats.

7. Integration tip: wrap it behind an interface. Given the package’s age and zero dependents, define your own LongRunner contract and adapt the package to it. If you later replace the package with a hand-rolled pcntl loop or Laravel’s native facilities, your application code does not change.

Gotchas and Tips

  • pcntl and posix are not universal. They are unavailable on Windows and often missing from slim Docker images. Install with docker-php-ext-install pcntl posix and guard signal registration with extension_loaded('pcntl'). Without it, SIGTERM will terminate the process immediately and your graceful shutdown is a lie.

  • Signals go to PID 1, not your PHP process. In Docker, if your entrypoint is a shell script, SIGTERM may never reach artisan. Use exec php artisan ..., or run with tini/dumb-init. In Supervisor, stopasgroup=true is usually required.

  • The package’s last release is December 2023 and it has zero dependents. Treat it as unmaintained until proven otherwise. Pin an exact version, run composer audit, skim the issue tracker for open signal/timeout bugs, and budget a spike day before committing production workloads. Check compatibility with your Laravel major version explicitly.

  • Monorepo version drift. Subpackages may be tagged independently. Do not mix long-running/core from one release with long-running/worker from another. Install the root package or lock all subpackages to the same tag, and verify with composer show | grep long-running.

  • config:cache will freeze your config. Use env() only inside config/long-running.php, never at runtime in the loop. If you change tuning values, run php artisan config:clear in development.

  • Database timeouts still apply. CLI max_execution_time is normally 0, but MySQL wait_timeout, PostgreSQL idle_in_transaction_session_timeout, and network load balancers will drop idle connections. Either reconnect proactively or set a keepalive query. Catch PDOException and reconnect rather than letting the process die.

  • Memory leaks are usually listeners, not your data. Eloquent model event listeners, Telescope, debugbar, and Monolog context all accumulate. Disable debug tooling in production workers, and be careful with Log::withContext() inside a loop.

  • Don’t rely on finally for signal handling. A SIGKILL skips finally blocks. Persist checkpoints during the work, not only on shutdown.

  • Graceful shutdown needs a deadline. Track when SIGTERM was received and force-exit if the current batch exceeds your configured grace period. Otherwise a stuck batch makes deploys hang until the orchestrator kills the pod.

  • Test the failure path explicitly. Send SIGTERM to a running process in staging and confirm: current batch finishes, checkpoint is written, heartbeat stops, and exit code is zero. This single test catches more problems than any config review.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin