Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

vrerabek's avatar

Best place to run `php artisan horizon:terminate` in Envoyer's deployment flow?

I'm using Envoyer for zero-downtime deployments, and I'm wondering where the best place is to run the php artisan horizon:terminate command.

Here's the deployment flow of Envoyer:

  1. Clone New Release
  2. Install Composer Dependencies (if configured)
  3. Activate New Release
  4. Purge Old Releases

I can't wrap my head around whether to run it before activating the new release or after activating the new release. Both seem to have it's downsides.

  • If I terminate Horizon before activating the new release, there might be a window where the old version of the app is still accessible, and old versions of jobs could be pushed into the queue.
  • If I terminate Horizon after activating the new release, there might be a window where the new version is live, but Horizon is still running with the old worker code.

How do you handle this in your deployment flow? Is there a better way to manage this? Am I overthinking it, or do I need to implement some kind of job versioning to handle this gracefully?

I am using Laravel Forge and have enabled Laravel Horizon there.

Any advice would be appreciated!

0 likes
1 reply
LaryAI's avatar
Level 58

When using Envoyer for zero-downtime deployments, the timing of running php artisan horizon:terminate is crucial to ensure that your workers are using the latest code without causing any downtime or inconsistencies.

Here's a recommended approach:

  1. Clone New Release: This step is straightforward and doesn't require any action related to Horizon.

  2. Install Composer Dependencies: Ensure all dependencies are up-to-date. This step is also independent of Horizon.

  3. Terminate Horizon Before Activating New Release:

    • Run php artisan horizon:terminate before activating the new release. This ensures that Horizon will gracefully terminate and restart with the new code once the new release is activated.
    • By terminating Horizon before activation, you minimize the risk of processing jobs with outdated code. Horizon will automatically restart with the new release once it's activated.
  4. Activate New Release:

    • After terminating Horizon, proceed to activate the new release. This will ensure that when Horizon restarts, it will be using the latest codebase.
  5. Purge Old Releases: This step is unrelated to Horizon and can proceed as usual.

By following this order, you ensure that Horizon is always running the latest code without any downtime. The key is to terminate Horizon just before activating the new release, so it restarts with the new code immediately after activation.

Here's a summary of the steps in code:

# Step 3: Terminate Horizon
php artisan horizon:terminate

# Step 4: Activate New Release
# (This is handled by Envoyer automatically)

This approach should help you maintain a smooth deployment process with zero downtime and ensure that your job processing is always up-to-date with the latest code.

Please or to participate in this conversation.