Skip to main content

atomic_directory_swap

⚙️ Atomic Directory Updates Using Temporary Directories

For zero-downtime deployments or safe configuration updates, stage changes in a temp directory and then atomically swap it with File.rename. This ensures consumers never see a half-written state.

require 'fileutils'
require 'tmpdir'

def atomic_update(target_dir)
Dir.mktmpdir(File.basename(target_dir), File.dirname(target_dir)) do |tmp|
tmp_path = Pathname.new(tmp)
# Stage new files
FileUtils.cp_r('build/output/.', tmp_path)

# Optionally set permissions or post-process
tmp_path.children.each { |p| FileUtils.chmod(0o644, p) if p.file? }

# Atomic swap: move old out, bring new in
backup = "#{target_dir}.bak"
FileUtils.rm_rf(backup)
FileUtils.mv(target_dir, backup)
FileUtils.mv(tmp_path, target_dir)

# Cleanup backup if all good
FileUtils.rm_rf(backup)
end
end

# Usage
atomic_update('/var/www/my_app/shared/config')

By leveraging Dir.mktmpdir and FileUtils.mv, you guarantee either the old directory or the new one is fully in place, avoiding partial states and ensuring rollback on failure.