whoami

Lucas Jenß

cat /etc/motd

The Coding Journal ツ — Notes taken on an epic coding journey. Technical solutions, debugging notes, and practical guides from the trenches of software development.

Close-up of white dominoes with black dots standing on green felt surface, shallow depth of field, focused mood

ls -la ~/languages/

total 8
drwxr-xr-x
▶ PHP
▶ Ruby
▶ Scala
▶ C#
▶ JavaScript
▶ Objective-C
▶ Shell Scripting

ls -la ~/toolchain/

total 7
drwxr-xr-x
▶ Typo3
▶ Akka
▶ Capistrano
▶ Git
▶ MAMP
▶ Adobe Illustrator
▶ NSTrackingArea (Cocoa)

uname -a

platforms
drwxr-xr-x
▶ Mac OS X
▶ Unix

Warm the Application Cache After a Capistrano Deploy

A Capistrano after-deploy hook can run a cache-warming command as part of a release, removing the need for an engineer to visit production and rebuild expensive data manually. A useful hook runs after the new release has been published and linked as current, but before the deployment is declared healthy.

The hook should orchestrate, not contain, the business logic. Give the application a tested command that prepares its data, then let Capistrano invoke that command with the correct environment and release. This keeps the warmer usable from a workstation, a CI pipeline, or an Australian support team working outside the deployment server.

Build the cache warmer in the application

Give the application one command that prepares every cache entry required immediately after a release. A Rails application might expose bin/rails cache:warm; a PHP application could provide an equivalent Artisan or console command. The important contract is consistent output, predictable completion, and a non-zero exit status when the cache is not safe.

# lib/tasks/cache.rake
namespace :cache do
  desc "Prepare cached catalogue data"
  task warm: :environment do
    CatalogueWarmer.new.call
  end
end

Adapt the task to the project rather than copying the example literally. It may rebuild navigation, product facets, pricing summaries, or search suggestions. Prefer deterministic keys and stable ordering so two runs produce the same result.

The warmer should be idempotent because Capistrano can retry a failed release. It should also be bounded by a timeout, write progress to the application log, and report how many entries were created. Build replacement values before removing old ones so a failed run does not leave production with an empty cache.

Wire the warmer into Capistrano

Keep the deployment-specific code in config/deploy.rb, while the warming logic remains in the application repository. A typical Capistrano 3 task looks like this:

set :rails_env, -> { fetch(:stage) }

namespace :app do
  desc "Warm the application cache"
  task :warm_cache do
    on roles(:app) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :bundle, "exec", :rake, "cache:warm"
        end
      end
    end
  end
end

after "deploy:published" do
  invoke! "app:warm_cache"
end

The after hook runs with release_path pointing at the newly published release. invoke! deliberately treats a failed warming command as a deployment failure, which is appropriate when application requests would otherwise overload the database or serve incorrect data.

roles(:app) normally runs the command on every application host. That is useful when each host has a local cache, but it can duplicate work when the target is one shared Redis or Memcached service. Assign one host to a dedicated warming role if the task is safe only once. For broader release sequencing, Mike Meredith's deployment workflow notes offer a useful reference.

Keep warmed data available across releases

A local cache under the release directory can disappear as soon as the next deployment creates a new release. If the application expects the warmed files to survive, link that directory into shared. For example:

set :linked_dirs, %w[log tmp/pids tmp/cache]

This gives the current release a stable path to tmp/cache, while Capistrano still supplies application code from the release directory. Check that the deploy user can write to the shared path and that stale files are removed deliberately when their schema or key format changes.

External caches need different safeguards. A Redis-backed catalogue might use namespaced keys such as catalogue:v12, while a Memcached deployment can rely on expiring entries. The warming task should write complete values, use atomic replacement where possible, and avoid deleting keys that another release still needs.

The hook also depends on production services being reachable. Database credentials, encryption keys, Redis authentication, and the correct RAILS_ENV must be available to the deploy user without printing secrets into command output. Test the task with the same runtime and configuration paths used by the application process.

Fail visibly without creating a rollback trap

A strict hook creates an operational decision. If warming is critical, let invoke! stop the release and alert the deployer. If the cache is only an optimisation, replacing invoke! with invoke may be safer than marking a healthy release as failed, provided monitoring raises an alert and the application can fall back to uncached reads.

Do not assume an automatic rollback will repair the cache. The new code may already be serving traffic, and cached values written by that code may no longer match the previous release. Decide whether rollback is appropriate for the application, then clear or rebuild the relevant namespace separately if the release is reversed.

Record the start time, finish time, entry count, and exit status for every warm-up. A small synthetic request can then check a known cache-backed page during the release. I also keep the author's TYPO3 upgrade troubleshooting notes nearby because upgrade failures need reproducible symptoms, not a hopeful cache clear that hides the real fault.

Fit the release into Australian operations

Australian release windows have their own practical details. Teams in Sydney, Melbourne, and Brisbane may agree on a mid-morning deployment, but Melbourne follows Sydney while Brisbane remains on AEST and does not change for daylight saving. Check the current AEST or AEDT offset before a release and avoid scheduling around the daylight-saving transition.

The cached data should reflect the Australian market as customers see it. For an .com.au shop, that may mean GST-inclusive prices, Australian dollar shipping estimates, postcode rules, and stock shown in local stores. Warming against an overseas locale can leave valid-looking prices or delivery promises in place until the first cache miss repairs them.

Use Australian spelling and dd/mm/yyyy dates in logs and test fixtures, and make sure a cache key changes when either changes. These details are easy to overlook in a global sample dataset. A release check performed from Sydney, Melbourne, and Brisbane also gives quick evidence that remote application servers can reach shared cache and database services.

Verify the release and keep the evidence

Run the warming task against staging data that resembles production, including large catalogues and the slowest supported database path. Capture its normal duration, memory use, and entry count. Those figures become a baseline, so an unusual slowdown in production is visible rather than hidden inside a successful SSH command.

Compare release timings before choosing the final policy:

Strategy Behaviour during release Main risk Suitable when
Clear after publish Deletes old values and rebuilds on demand Cold reads and extra database load Values are cheap to recreate
Warm after publish Builds replacement values while the new release is live A brief mixed state The task is fast and idempotent
Warm before publish Builds values in the candidate release before traffic moves A failure blocks the release The release and cache models are compatible
Background refresh Rebuilds values after traffic resumes Stale values may persist briefly The cache is not correctness-critical

Make the hook observable in production, compare it with the baseline, and confirm that a cache-backed request returns the expected data before declaring the release healthy.

Add the application warming command to the repository, test it with representative staging data, and attach it to deploy:published only after both checks pass. Ship the tested hook with the next release and keep an owner ready to inspect cache metrics and deployment logs if the Australian release window needs to pause.


cat ~/interests.json

KeyValue
editorTerminal-first workflow
osMac OS X / Unix
vcsGit, distributed version control
deployCapistrano, cron automation
graphicsSVG, Adobe Illustrator troubleshooting
networkingIP validation, SSH, VPN

git log --oneline --reverse

2013-10-30

Solving SVG import issues in Adobe Illustrator CS6 and CC

When importing an SVG into Illustrator, the operation fails with an unknown error [CANT]. A workaround for this Adobe-side bug.

2013

Solving NDK build issues on OS X

Troubleshooting native development kit compilation problems on Mac OS X.

2013

Programmatically adding PHP generated TypoScript to the backend configuration

Integrating dynamically generated TypoScript into Typo3 backend setups using PHP.

2013

ArgumentError: Could not parse PKey: no start line

Debugging an SSH key parsing error encountered during deployment.

2011-08-04

Validating IP-Addresses in PHP

Using PHP filter functions with flags like FILTER_FLAG_IPV4 and FILTER_FLAG_IPV6, and understanding how filter_var handles reserved IP addresses.

2011-07-09

Cocoa: Using NSTrackingArea

A short tutorial on using Cocoa's NSTrackingArea to capture mouseEntered and mouseExited events.


cat ~/contact.txt

github: github.com/x3ro
stackoverflow: x3ro
coderwall: coderwall.com/x3ro
twitter: @x3rames