Container orchestration is the fashionable answer and a release directory with a symlink is still the right one for a single application on one or two hosts.
release="/var/www/app/releases/$(date +%Y%m%d%H%M%S)"
rsync -a --delete --exclude-from=.deployignore ./ "$release/"
ln -sfn /var/www/app/shared/.env "$release/.env"
ln -sfn /var/www/app/shared/storage "$release/storage"
ln -sfn "$release" /var/www/app/current.tmp
mv -Tf /var/www/app/current.tmp /var/www/app/current
systemctl reload php7.3-fpm
mv -T on a symlink is a rename and therefore atomic on the same filesystem; ln -sfn straight onto an existing link is not, and there is a window where the path does not resolve. The fpm reload is required rather than optional, because opcache keys on the resolved path and without it the workers keep serving the previous release from memory. Rolling back is repointing the link, which takes a second.