Skip to content

Add zero-downtime deployment support with symlinks#1111

Draft
JoshSalway wants to merge 3 commits intolaravel:2.xfrom
JoshSalway:fix/octane-1004
Draft

Add zero-downtime deployment support with symlinks#1111
JoshSalway wants to merge 3 commits intolaravel:2.xfrom
JoshSalway:fix/octane-1004

Conversation

@JoshSalway
Copy link
Copy Markdown

@JoshSalway JoshSalway commented Mar 22, 2026

Summary

When deploying with symlink-based strategies (Deployer, Envoyer), Octane workers resolve the real path at startup and continue loading files from the old release directory after the symlink is switched. This means code changes are never picked up, even after octane:reload.

Fixes #1004

Problem

Octane workers call realpath() on the working directory at boot time. In symlink deployments, current -> releases/v1 resolves to /var/www/releases/v1. After deploying v2 and switching current -> releases/v2, octane:reload still resolves the cached real path, so workers continue serving v1 code.

/var/www/current -> /var/www/releases/v1  (before deploy)
/var/www/current -> /var/www/releases/v2  (after deploy)

# Octane worker still uses /var/www/releases/v1 because realpath() was cached

Solution

  • Add ResolvesSymlinks trait that detects symlinked working directories and passes the logical path (not the resolved real path) to Swoole, RoadRunner, and FrankenPHP server processes
  • Clear stat cache on octane:reload and Swoole beforeReload so symlinks are re-resolved
  • Update Swoole bin scripts to use configurable bin directory via APP_RELEASE_BIN_DIR env var

Test Plan

  • ResolvesSymlinksTest included covering symlink detection and path resolution
  • Manual testing: deploy with Deployer using symlinked current directory, run octane:reload, verify new release code is loaded
  • Non-symlinked deployments are unaffected (trait detects non-symlink and no-ops)

@github-actions
Copy link
Copy Markdown

Thanks for submitting a PR!

Note that draft PRs are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface.

Pull requests that are abandoned in draft may be closed due to inactivity.

Josh Salway and others added 3 commits March 23, 2026 09:47
When deploying with symlink-based strategies (Deployer, Envoyer),
Octane workers resolve the real path and continue loading files
from the old release after the symlink is switched.

Add a ResolvesSymlinks trait that detects symlinked working
directories and passes the logical path to server processes.
Clear stat cache on reload so symlinks are re-resolved.
Update Swoole bin scripts to use configurable bin directory.

Fixes laravel#1004

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove superfluous @return phpdoc tag (type hint is sufficient)
- Remove extra blank line in StartRoadRunnerCommand
- Fix anonymous class brace position in test
- Use $basePath instead of base_path() for RoadRunner server.command path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The PR description claimed FrankenPHP support but StartFrankenPhpCommand
was not using the ResolvesSymlinks trait. This adds the trait and
replaces base_path() with ->resolveBasePath() for the process
working directory, APP_BASE_PATH, APP_PUBLIC_PATH, and watch paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No ability to deploy without downtime

1 participant