No middleware without touching RACK_ENV

Lin Jen-Shin (godfat) godfat at godfat.org
Fri Jan 25 10:52:29 UTC 2013


Hi,

This might be a bit silly, but finally I decided to bring this up.

We're running a Rails app along with another Rack app in
the same config.ru, and what I want to do is telling Unicorn
that we don't want any middleware which Unicorn might
insert with RACK_ENV=development and RACK_ENV=
deployment, because we're adding Rack::CommonLogger
and other middleware by ourselves, while we're using
RACK_ENV=development for Rails when developing.

That is, we want to use RACK_ENV=development for Rails
because that's how it used to be, but we also don't want
those additional middleware got inserted automatically.
This has no problem with RACK_ENV=production.

I know this is somehow a spec from Rack, but I guess I
don't like this behaviour. One workaround would be
providing a `after_app_load' hook, and we add this to
the bottom of config.ru:

  ENV['RACK_ENV_ORIGINAL'] = ENV['RACK_ENV']
  ENV['RACK_ENV'] = 'none'

and add this to the unicorn configuration file:

  after_app_load do |_|
    ENV['RACK_ENV'] = ENV['RACK_ENV_ORIGINAL']
  end

This is probably a stupid hack, but I wonder if after_app_load
hook would be useful for other cases?

Or if we could have an option to turn off this Rack behaviour
simulation, like:

    default_middleware false

That might be more straightforward for what we want. Oh but
it seems it's not that easy to add this. What about an option
for unicorn?

    unicorn -E development -N

or

    unicorn -E development --no-default-middleware

This would need to be applied to `rainbows' and `zbatery', too,
though. Patches below for consideration:
(Sorry if Gmail messed the format up, but from last time
I tried, it doesn't accept attachments :( What's the best way?
Links to raw patches?)

https://github.com/godfat/unicorn/pull/2

commit 95de5abf38a81a76af15476d4705713d2d644664
Author: Lin Jen-Shin <godfat at godfat.org>
Date:   Fri Jan 25 18:18:21 2013 +0800

    Add `after_app_load' hook.

    The hook would be called right after application is loaded.

diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index 7651093..332bdbc 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -43,6 +43,9 @@ class Unicorn::Configurator
     :before_exec => lambda { |server|
         server.logger.info("forked child re-executing...")
       },
+    :after_app_load => lambda { |server|
+        server.logger.info("application loaded")
+      },
     :pid => nil,
     :preload_app => false,
     :check_client_connection => false,
@@ -171,6 +174,13 @@ class Unicorn::Configurator
     set_hook(:before_exec, block_given? ? block : args[0], 1)
   end

+  # sets the after_app_load hook to a given Proc object.  This
+  # Proc object will be called by the master process right
+  # after application loaded.
+  def after_app_load(*args, &block)
+    set_hook(:after_app_load, block_given? ? block : args[0], 1)
+  end
+
   # sets the timeout of worker processes to +seconds+.  Workers
   # handling the request/app.call/response cycle taking longer than
   # this time period will be forcibly killed (via SIGKILL).  This
diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb
index aa98aeb..a3b30ee 100644
--- a/lib/unicorn/http_server.rb
+++ b/lib/unicorn/http_server.rb
@@ -14,6 +14,7 @@ class Unicorn::HttpServer
   # :stopdoc:
   attr_accessor :app, :request, :timeout, :worker_processes,
                 :before_fork, :after_fork, :before_exec,
+                :after_app_load,
                 :listener_opts, :preload_app,
                 :reexec_pid, :orig_app, :init_listeners,
                 :master_pid, :config, :ready_pipe, :user
@@ -716,6 +717,7 @@ class Unicorn::HttpServer
         Gem.refresh
       end
       self.app = app.call
+      config.after_app_load.call(self)
     end
   end






And --no-default-middleware
https://github.com/godfat/unicorn/pull/3

commit e3575db2a36e3ca2acda18bfee97bf95609a9860
Author: Lin Jen-Shin <godfat at godfat.org>
Date:   Fri Jan 25 18:38:52 2013 +0800

    Add -N or --no-default-middleware option.

    This would prevent Unicorn from adding default middleware,
    as if RACK_ENV is always none. (not development nor deployment)

    This should also apply to `rainbows' and `zbatery'.

diff --git a/bin/unicorn b/bin/unicorn
index 9962b58..415d164 100755
--- a/bin/unicorn
+++ b/bin/unicorn
@@ -58,6 +58,11 @@ op = OptionParser.new("", 24, '  ') do |opts|
     ENV["RACK_ENV"] = e
   end

+  opts.on("-N", "--no-default-middleware",
+          "no default middleware even if RACK_ENV is development") do |e|
+    rackup_opts[:no_default_middleware] = true
+  end
+
   opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
     rackup_opts[:daemonize] = !!d
   end
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index d96ff91..f0ceffe 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -49,6 +49,8 @@ module Unicorn

       pp({ :inner_app => inner_app }) if $DEBUG

+      return inner_app if op[:no_default_middleware]
+
       # return value, matches rackup defaults based on env
       # Unicorn does not support persistent connections, but Rainbows!
       # and Zbatery both do.  Users accustomed to the Rack::Server default


More information about the mongrel-unicorn mailing list