You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Magento] maintenance:disable runs before deploy:symlink, so the old release serves the upgraded database
#4261
In deploy:magento, magento:maintenance:disable runs straight after magento:config:import and magento:upgrade, but the release only goes live later at deploy:symlink. Since the maintenance flag lives in the old release's own var/, lifting it hands traffic back to the old code while the database and config already belong to the new release. On our production deploy that gap returned 500 "The configuration file has changed" to real visitors in the second or two before the switch.
Two related cases:
Re-deploy after a partial failure. If a deploy fails after the import/upgrade has written, the follow-up re-deploy has nothing pending, so the group lifts the old release's flag before the switch and it serves the already-changed database again. A flag set during the failed run can't prevent this, because it doesn't survive into the next dep run.
Failure path.deploy:magento:failed reimports config on current and lifts maintenance. That covers a config-only change, but after setup:db-schema:upgrade it puts the old code back on the new schema.
To reproduce: deploy a release with a config.php change (or a schema change) using the stock recipe while polling the storefront; requests between magento:maintenance:disable and deploy:symlink hit the old code against the new config.
Proposed fix
Drop magento:maintenance:disable from deploy:magento. With enable_zerodowntime on, magento:maintenance:enable-if-needed only puts the old release into maintenance when a config import or DB upgrade is pending, and the new release never carries the flag (it isn't shared, see #2940), so the site comes back exactly at deploy:symlink and nothing needs lifting. That also fixes the re-deploy case. On the failure path, after('deploy:failed', 'magento:maintenance:disable') should skip the disable when a write was pending. Code-only zero-downtime deploys are unchanged. Trade-off: a dep rollback after a schema change lands on the maintenance page, which seems right, since the old code can't run on that database.
What we run, tested on a real host with injected failures: the group redeclared without the disable (hooks attached to deploy:magento survive, since task() with an array calls setGroup()), a task before magento:config:import that records "write pending", and a magento:maintenance:disable override that returns early when it's set. Results: no old-release errors around the switch; on a failure after the write, the site stays on the maintenance page and the lock is released; on the re-deploy, only maintenance responses before the switch.
Happy to open a PR along those lines if that works for you.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Deployer Version
v7.5.12 (the same code is on master and v8.0.5)
Target OS
cPanel on a RHEL 9-family kernel (el9_7)
Which PHP version are you using?
PHP 8.2
Steps to reproduce
In
deploy:magento,magento:maintenance:disableruns straight aftermagento:config:importandmagento:upgrade, but the release only goes live later atdeploy:symlink. Since the maintenance flag lives in the old release's ownvar/, lifting it hands traffic back to the old code while the database and config already belong to the new release. On our production deploy that gap returned 500 "The configuration file has changed" to real visitors in the second or two before the switch.Two related cases:
deprun.deploy:magento:failedreimports config on current and lifts maintenance. That covers a config-only change, but aftersetup:db-schema:upgradeit puts the old code back on the new schema.To reproduce: deploy a release with a config.php change (or a schema change) using the stock recipe while polling the storefront; requests between
magento:maintenance:disableanddeploy:symlinkhit the old code against the new config.Proposed fix
Drop
magento:maintenance:disablefromdeploy:magento. Withenable_zerodowntimeon,magento:maintenance:enable-if-neededonly puts the old release into maintenance when a config import or DB upgrade is pending, and the new release never carries the flag (it isn't shared, see #2940), so the site comes back exactly atdeploy:symlinkand nothing needs lifting. That also fixes the re-deploy case. On the failure path,after('deploy:failed', 'magento:maintenance:disable')should skip the disable when a write was pending. Code-only zero-downtime deploys are unchanged. Trade-off: adep rollbackafter a schema change lands on the maintenance page, which seems right, since the old code can't run on that database.What we run, tested on a real host with injected failures: the group redeclared without the disable (hooks attached to
deploy:magentosurvive, sincetask()with an array callssetGroup()), a task beforemagento:config:importthat records "write pending", and amagento:maintenance:disableoverride that returns early when it's set. Results: no old-release errors around the switch; on a failure after the write, the site stays on the maintenance page and the lock is released; on the re-deploy, only maintenance responses before the switch.Happy to open a PR along those lines if that works for you.
All reactions