Tag: apache2

Apache (Passenger) Maintenance mode for Ruby on Rails application with Capistrano

Same of Nginx and Puma: Nginx (and Puma behind) maintenance mode for Rack/Rails applications with Capistrano

There is a time, when we need to switch our apps into maintenance mode. Maybe it is because of some data processing stuff, maybe because of backups, Capistrano or whatever good reason you might have. To be honest it doesn't matter why. What does matter, is how we should handle working users of our apps. Of course all the downtimes should take place when there is the smallest amount of users online. In most cases it might be a good idea to switch application off in the middle of the night (or on Sunday, etc.), but this won't solve our primary problem: what should we show users that are already online?

The worst scenario ever would be showing them nothing (for example by shutting down whole application server). Users probably will think, that something bad happened. Much better idea is to show users a maintenance page with some sort of information like "Temporary down for maintenance". It would be even better, it such a page would automatically show when needed.

To do so, we can use Apache Mod Rewrite module and a static 503.html page.

Mod Rewrite for Maintenance mode detection

How to determine if we are in maintenance mode? Let's check if maintenance.txt file exists in tmp/ dir of our app:

RewriteCond %{DOCUMENT_ROOT}/../tmp/maintenance.txt !-f

When it exists, we need to redirect user to our 503.html static page:

RewriteRule ^(.*)$ /503.html [NC,R,L]

Of course the whole .htaccess should include also enabling RewriteEngine, ignoring redirects of CSS files and redirecting from 503.html to root, when the maintenance is off:

RewriteEngine On
# Set error 503 static page
ErrorDocument 503 /503.html

# Don't redirect when someone requests assets used in 503.html
RewriteCond %{REQUEST_URI} !^/assets/layouts/portal/favicon.ico$
RewriteCond %{REQUEST_URI} !^/assets/libraries/bootstrap/bootstrap.min.css$
RewriteCond %{REQUEST_URI} !^/assets/layouts/portal/application.css$
RewriteCond %{REQUEST_URI} !^/503.html$
RewriteCond %{DOCUMENT_ROOT}/../tmp/maintenance.txt -f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
# Set 503 status for all requests
RewriteRule ^(.*)$ /503.html [NC,R=503,L]

# When it is not maintenance mode redirect to root_path from 503.html
RewriteCond %{DOCUMENT_ROOT}/../tmp/maintenance.txt !-f
RewriteCond %{REQUEST_URI} ^/503.html
RewriteRule ^503.html http://www.project.domain/ [R=302,L]

Of course, you need to remember to create your own 503.html file, put it in public/ dir of your project and customize all the htaccess rules based on your needs.

Capistrano hookup

To automate enabling and disabling my projects, I use a set of simple Capistrano tasks, enclosed in an Apache namespace:

namespace :apache do

  desc 'Restarts the current Passenger project'
  task :restart do
    run "touch #{current_path}/tmp/restart.txt"
  end

  desc 'Sets project server in dev mode - so the 503 page is served'
  task :lock do
    run "touch #{current_path}/tmp/maintenance.txt"
  end

  desc 'Sets project to a standard mode'
  task :unlock do
    run "rm -f #{current_path}/tmp/maintenance.txt"
  end

end

Usage example:

before 'deploy:update' do
  apache.lock
end

after 'deploy:update' do
  apache.restart
  apache.unlock
end

That's all. Good luck and as few maintenance downtime as possible! P.S. With a bit of modifications, this code might be used also for PHP/Python Passenger based projects.

PhusionPassenger::UnknownError: Psych::SyntaxError – tab character that violate intendation

Yesterday I've started (after trying to restart Passenger) to see this exception coming out from Apache error.log:

[ pid=5098 thr=5896300 file=utils.rb:176 time=2012-08-31 19:00:45.293 ]:
*** Exception PhusionPassenger::UnknownError in 
PhusionPassenger::ClassicRails::ApplicationSpawner ((<unknown>): 
found a tab character that violate intendation while scanning a plain scalar at line 49 in 11
(Psych::SyntaxError)) (process 5098, thread #<Thread:0x00000000b3f0d8>):

Passenger ApplicationSpawner was endlessly creating new instances of my app, because the previous onces needed to be shutdown because of this error. It was quite obvious for me, that the error came from invalid yaml file (Psych::SyntaxError), however stack trace looked like this:

from /usr/local/lib/ruby/1.9.1/psych.rb:203:in `parse'
from /usr/local/lib/ruby/1.9.1/psych.rb:203:in `parse_stream'
from /usr/local/lib/ruby/1.9.1/psych.rb:151:in `parse'
from /usr/local/lib/ruby/1.9.1/psych.rb:127:in `load'
from /gems/settingslogic-2.0.8/lib/settingslogic.rb:114:in `initialize'
from /gems/settingslogic-2.0.8/lib/settingslogic.rb:71:in `new'
from /gems/settingslogic-2.0.8/lib/settingslogic.rb:71:in `instance'
from /gems/settingslogic-2.0.8/lib/settingslogic.rb:77:in `method_missing'
from /home/httpd/v5.senpuu.net/releases/20120829194758/config/initializers/resque.rb:5
from /gems/activesupport-3.2.8/lib/active_support/dependencies.rb:245:in `load'
from /gems/activesupport-3.2.8/lib/active_support/dependencies.rb:245:in `block in load'
from /gems/activesupport-3.2.8/lib/active_support/dependencies.rb:236:in `load_dependency'
from /gems/activesupport-3.2.8/lib/active_support/dependencies.rb:245:in `load'
from /gems/railties-3.2.8/lib/rails/engine.rb:588:in `block (2 levels) in <class:Engine>'
from /gems/railties-3.2.8/lib/rails/engine.rb:587:in `each'
from /gems/railties-3.2.8/lib/rails/engine.rb:587:in `block in <class:Engine>'
from /gems/railties-3.2.8/lib/rails/initializable.rb:30:in `instance_exec'
from /gems/railties-3.2.8/lib/rails/initializable.rb:30:in `run'
from /gems/railties-3.2.8/lib/rails/initializable.rb:55:in `block in run_initializers'
from /gems/railties-3.2.8/lib/rails/initializable.rb:54:in `each'
from /gems/railties-3.2.8/lib/rails/initializable.rb:54:in `run_initializers'
from /gems/railties-3.2.8/lib/rails/application.rb:136:in `initialize!'
from /gems/railties-3.2.8/lib/rails/railtie/configurable.rb:30:in `method_missing'

Ok, bot how to find the file with invalid yaml syntax? In my case, this exception was raised when SettingsLogic could not parse the given yaml file. So I've decided to hookup into it, just before the parsing, so I would be able to print out the invalid file. To do so I've edited /gems/settingslogic-2.0.8/lib/settingslogic.rb file. If you go to line 114 of this file, you will see something like this:

hash = YAML.load(ERB.new(File.read(hash_or_file)).result).to_hash
if self.class.namespace
  hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}")
end

So in order to print the invalid file name we just need to add:

p hash_or_file

just before the YAML.load method execution. After this, it was really easy to find an invalid line in my yaml file.

Copyright © 2024 Closer to Code

Theme by Anders NorenUp ↑