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

Laravel Horizon Restart Laravel Package

huangdijia/laravel-horizon-restart

A lightweight Laravel package for restarting Horizon workers programmatically or from an Artisan command. Useful after deployments or config changes, it sends Horizon's restart signal so workers reload gracefully without manual intervention.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require huangdijia/laravel-horizon-restart. The service provider is auto-discovered; there is nothing to register in config/app.php on any supported Laravel version.
  • Prerequisite: Laravel Horizon must already be installed, configured, and running for the target environment. This package is a thin orchestration layer over Horizon's own pause/terminate/continue lifecycle — it does not replace Horizon and does nothing on its own.
  • Confirm the command registered: php artisan list | grep horizon. You should see the package's restart command alongside Horizon's stock horizon:terminate, horizon:pause, and horizon:continue.
  • First use case: replace php artisan horizon:terminate in your deploy script with the package's restart command. The stock terminate kills workers immediately, dropping any job that is mid-flight; the package's restart drains in-flight work first, which is what you actually want on a deploy that ships changed job/handler code.
  • Where to look first: vendor/huangdijia/laravel-horizon-restart/src/ — read the single command class end to end (it is small) to see exactly which Horizon lifecycle calls it makes and in what order. Then check php artisan horizon:status to confirm Horizon is actually running before you test the restart, otherwise the command will appear to hang or no-op.
  • v3.1.0 specifically: this is a compatibility-only release (Laravel 12.x + PHP 8.4 constraint widening). There are no API, command-signature, or behavioural changes against v3.0.0, so existing deploy hooks keep working unchanged.

Implementation Patterns

  • Deploy hook (the primary pattern). Add the restart as the last step of the release, after artisan migrate --force and after the new code is symlinked in and php artisan config:cache has run:
    php artisan migrate --force
    php artisan config:cache
    php artisan horizon:restart
    
  • Ordering versus the symlink switch. Run the restart after the new release is live. Horizon's master supervisor respawns worker processes from the currently-resolved code path, so restarting before the symlink flip just respawns old code. If you run it before, you need a second restart after.
  • Pair with queue:restart only for non-Horizon connections. Horizon-managed Redis queues are covered by the restart command; SQS/database queues handled by plain queue:work supervisors are not, so keep a php artisan queue:restart for those.
  • Programmatic invocation. It is a normal artisan command, so Artisan::call('horizon:restart') works from a deploy webhook controller, a php artisan app:deploy wrapper command, or a scheduled job. Wrap it in a queued job with ->onOneServer() if you trigger deploys from multiple app servers.
  • CI/CD integration. In GitHub Actions / GitLab CI, invoke it as a remote step over SSH against an app host rather than from the build container — the command needs the app's .env, Redis credentials, and the same APP_ENV as the running Horizon.
  • Deployer / Envoyer. In deploy.php use task('horizon:restart', ...)->run('{{release_path}}/artisan horizon:restart') and hang it off deploy:symlink. In Envoyer, add it as an Activate New Release hook.
  • Guard for "Horizon not running". On fresh environments or during scale-to-zero, the restart is meaningless. Pattern: php artisan horizon:status | grep -q running && php artisan horizon:restart || true so a first deploy doesn't fail the pipeline.
  • Time-boxed graceful drain. For deploys with a hard CI timeout, run the restart with a bounded wait and fall back to a hard terminate if it overruns, so a stuck job can't block a release forever.

Gotchas and Tips

  • Environment/Redis mismatch is the number one failure mode. The command coordinates through the same Redis connection Horizon's master supervisor uses. If APP_ENV, REDIS_*, or the horizon.php connection differ between where you run the command and where Horizon runs, it will pause nothing and wait forever (or return instantly having done nothing). Always run it on a host with the production .env.
  • A killed restart can leave Horizon paused. If the CI job is cancelled or the SSH session drops mid-restart, Horizon may be left in the paused state and your queues silently stop processing. Add php artisan horizon:continue in a finally/|| cleanup step, and alert on queue depth so this surfaces fast.
  • Long jobs vs. deploy timeouts. The whole point is to drain in-flight work, but a 10-minute job will hold the restart for 10 minutes. Set ->timeout() on your CI step and decide explicitly whether a timeout should fail the deploy or hard-terminate (horizon:terminate) and accept job loss.
  • Supervisor coverage. Nothing restarts if the current environment has no supervisor defined in config/horizon.php under environments. Check that block before debugging the package.
  • Config cache. Run php artisan config:cache before the restart so respawned workers pick up the new config — and remember Horizon reads config/horizon.php at boot, so a config change without a restart is inert.
  • Containerised/Kubernetes deployments. If Horizon runs in its own pod, a rolling restart of that deployment is the idiomatic mechanism; the artisan command adds little and risks operating on a pod that's already terminating.
  • Debugging. Run with -vvv, tail storage/logs/laravel.log, and cross-check php artisan horizon:status / the Horizon dashboard's "paused" indicator before and after. If jobs stop processing after a deploy, checking the paused state is the first thing to do.
  • Version pinning for Laravel 12 / PHP 8.4. v3.1.0 only widened the illuminate/* and php constraints. If you're on Laravel 12 or PHP 8.4 with v3.0.0 pinned, Composer will refuse to resolve — bump to ^3.1. Conversely, on Laravel 10/11 there is no functional reason to rush the upgrade.
  • Extension points are minimal by design. There is no event dispatched around the restart and no config surface worth publishing; if you need conditional logic (skip when Horizon is paused, notify Slack after drain, custom drain thresholds), implement it in your own wrapper command rather than expecting the package to expose hooks.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib