Rails 3 suggest deploying with Bundler. Web applications using Bundler
have all their dependencies bundled, including Rack. Thus, they don't
even have to load Rubygems. Still, they might have different Rack
versions. Rails 2.3.5 application will bundle different Rack than
Rails 3.0.
So what I'm asking is can multiple applications be deployed on the
same server, each bundling their own version of Rack?
If not—what's the best approach to deploying apps that require edge
Rack (like Rails 3.0). Do we constantly need to build edge Rack gem
and install it on the system we're deploying to, so that Passenger can
use it? Wouldn't that mean edge Rack will be used for all web apps on
the same server, even those which don't require it?
I'm not familiar with how Passenger works and why does it have Rack as
dependency. I know I can edit the PassengerRuby directive to point to
a wrapper script that executes Ruby while loading the app-specific
vendor/gems/environment.rb file generated by Bundler, which will
probably make Passenger use the Rack version bundled by this app, but
this locks Passenger to only running this single app. It would be
ideal if PassengerRuby wouldn't have to be edited, but that still each
webapp starts as a clean ruby process and then it is determined if it
bundles its own Rack or, if not, Rubygems—and from them Rack—have to
be loaded.
It works like this: Phusion Passenger has two different loaders, a
Rails one and a Rack one. If config.ru exists then the app is detected
as a Rack app and the Rack loader will kick in. Otherwise, if
config/environment.rb exists then the app is detected as a Rails app
and the Rails loader will kick in. config.ru has precedence over
config/environment.rb.
The Rack loader will run 'require rack' before evaluating config.ru,
since config.ru assumes a Rack::Builder DSL environment, and
Rack::Builder is a part of the Rack library. Because of this Phusion
Passenger *has* to have a dependency on Rack. The code in question is
as follows:
rackup_code = ::File.read("config.ru")
eval("Rack::Builder.new {( #{rackup_code}\n )}.to_app",
TOPLEVEL_BINDING, "config.ru")
As you can see, there's no way to get rid of the 'require rack' part
because we depend on Rack::Builder before evaluating config.ru. Thin
suffers from the same problem:
[hongli@Minato lib (master)]$ rak "'rack'"
thin.rb
39|require 'rack'
Thin's Rackup file loading code looks very similar to Phusion
Passenger's (controller.rb #load_rackup_config):
rackup_code = File.read(@options[:rackup])
eval("Rack::Builder.new {( #{rackup_code}\n )}.to_app",
TOPLEVEL_BINDING, @options[:rackup])
I suspect that Unicorn and probably every Rack web server out there
suffers from the problem: Rack must be loaded in order to evaluate
config.ru, but further down the executation timeline config.ru
actually depends on a different Rack version.
The Rails loader does not suffer from this problem because it does not
run 'require rack', but I haven't tested the Rails loader against
Rails 3 yet.
Are you running Rails 3 with or without config.ru?
There are three solutions that I can think of:
- Making the Rails loader work with Rails 3. The implication of this
is that if you want to use a custom config.ru for your Rails 3 app
then you must install the required Rack version as a gem.
- Introduce a "RackVersion" or "RackPath" configuration option, so
that Phusion Passenger knows where to load Rack from. I really detest
this solution and would prefer not to go through this route.
- Seperate Rack::Builder into a separate library. However, this would
imply that config.ru will have to run 'require rack' if it wants to
use any other Rack code.
What do you think?
--
Phusion | The Computer Science Company
Web: http://www.phusion.nl/
E-mail: in...@phusion.nl
Chamber of commerce no: 08173483 (The Netherlands)
It looks like Phusion Passenger's Rails loader is compatible with Rails 3.
With. The Rails 3 app generator makes one; I didn't think of removing
it.
> There are three solutions that I can think of:
> - Making the Rails loader work with Rails 3. The implication of this
> is that if you want to use a custom config.ru for your Rails 3 app
> then you must install the required Rack version as a gem.
Does Passenger do some optimizations when detecting Rails apps as
opposed to Rack apps? If not, I'd rather keep using Rack loader for
Rails 3 apps so that eventually all Ruby webapps that I might run are
spawned the same way. It feels right. And as for the issue we're
discussing here, a solution should be something else that doesn't
special-case Rails apps.
> - Introduce a "RackVersion" or "RackPath" configuration option, so
> that Phusion Passenger knows where to load Rack from. I really detest
> this solution and would prefer not to go through this route.
I wanted to propose a new directive, but much more generic than
RackPath. When I run scripts in an app that uses Bundler, I'm doing
this:
$ ruby -r vendor/gems/environment path/to/script.rb
Here, the "environment.rb" is a Bundler-generated file that bootstraps
the environment (LOAD_PATH, to be exact). So, I'm telling the Ruby
interpreter "run this script, but load another script first". As far
as I know, there's no way of telling Passenger to do this without
setting PassengerRuby to a wrapper script, which is not a good-enough
solution because it's per-server, not per-app. If there was a per-app
directive that makes Passenger load a script *before* it requires Rack
and loads config.ru, we could use it for Bundler.
<VirtualHost *:80>
ServerName example.com
DocumentRoot "/my/app/public"
RackEnv development
RubyOpt "-r /my/app/vendor/gems/environment"
</VirtualHost>
I tried using RUBYOPT, just for kicks:
SetEnv RUBYOPT "-r /my/app/vendor/gems/environment"
Didn't seem to work. Rack is still loaded from Rubygems.
> - Seperate Rack::Builder into a separate library. However, this would
> imply that config.ru will have to run 'require rack' if it wants to
> use any other Rack code.
Not sure. Then we're back to vendoring Rack (at least one part of it).
Yes it does. All the Ruby Enterprise Edition memory saving and reduced
spawn time optimizations are only possible with the Rails loader. The
exact mechanisms are described in various documents:
http://www.modrails.com/documentation/Users%20guide%20Apache.html#spawning_methods_explained
http://www.modrails.com/documentation/Architectural%20overview.html
By using the Rack loader you will lose all of those advantages. This
is one of the main reasons why the Rails loader still exist; it's not
just for compatibility with Rails <= 2.1.
> I wanted to propose a new directive, but much more generic than
> RackPath. When I run scripts in an app that uses Bundler, I'm doing
> this:
>
> $ ruby -r vendor/gems/environment path/to/script.rb
>
> Here, the "environment.rb" is a Bundler-generated file that bootstraps
> the environment (LOAD_PATH, to be exact). So, I'm telling the Ruby
> interpreter "run this script, but load another script first". As far
> as I know, there's no way of telling Passenger to do this without
> setting PassengerRuby to a wrapper script, which is not a good-enough
> solution because it's per-server, not per-app. If there was a per-app
> directive that makes Passenger load a script *before* it requires Rack
> and loads config.ru, we could use it for Bundler.
Sounds like a good idea. Phusion Passenger can just load
vendor/gems/environments if it exists, without any config options.
Oops, looks like I made a mistake; the Rails loader doesn't work with
Rails 3 after all. We'll release a fix soon.
It might be a good idea, but you have to keep in mind that Bundler
users can change that location to something else. Popular location for
Rails 2 apps is "vendor/bundler_gems/environment", for instance. Then
again, it might be something completely else, so Passenger has to
expose some directive for configuring it -- a directive which says
"run this script before anything else". Then we can use Bundler or any
other library/tool for managing LOAD_PATH and we don't need Rubygems +
system gems anymore.
It looks like the bundler will become the de facto standard bundling
tool. I'm thinking about full integration: parse the Gemfile and
figure out where the bundle location is, and load the gems from there
before booting the app. Let's keep things DRY.
vendor/bundler_gems was the old location. The latest bundler README
does not mention changing the location for Rails.
Then you need to vendor Bundler? Or you will eval Gemfile in a scope
where only `bundle_path` is defined (to capture the path)?
> vendor/bundler_gems was the old location. The latest bundler README
> does not mention changing the location for Rails.
People are using "vendor/bundler_gems" for Rails 2 because "vendor/
gems" is a special path where Rails 2 initializer expected to find
unpacked gems in. If Bundler writes to "vendor/gems", Rails 2 apps
complain on boot (but otherwise work).
It's great that you intend to support Bundler out-of-the-box, but I'd
still like the feature with which I can set a script to load
immediately after the ruby interpreter has started. This is to support
other LOAD_PATH tools alternative to Bundler.
SetEnv environment data is passed to Phusion Passenger during a
request. But the Ruby spawn server is started during Apache startup,
before the first request comes in, therefore there's no good way to
pass SetEnv data like that.
> It's great that you intend to support Bundler out-of-the-box, but I'd
> still like the feature with which I can set a script to load
> immediately after the ruby interpreter has started. This is to support
> other LOAD_PATH tools alternative to Bundler.
At this time it's already possible by writing a Ruby wrapper script.
I'm thinking about depending on bundler, or maybe taking over its DSL
implementation. Don't need more than that.
At this time it's already possible by writing a Ruby wrapper script.
I will take note of this. Seems like something we will want to tackle
some time in the future.
On Thu, Jan 7, 2010 at 10:41 PM, Mislav Marohnić
<mislav....@gmail.com> wrote:
> But as I said, this can be only be accomplished per-server, not per-app,I will take note of this. Seems like something we will want to tackle
> making it a severly limited solution.
some time in the future.
--
Phusion | The Computer Science Company
Web: http://www.phusion.nl/
E-mail: in...@phusion.nl
Chamber of commerce no: 08173483 (The Netherlands)
--
You received this message because you are subscribed to the Google Groups "Phusion Passenger Discussions" group.
To post to this group, send email to phusion-...@googlegroups.com.
To unsubscribe from this group, send email to phusion-passen...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/phusion-passenger?hl=en.
For Phusion Passenger 2.2, this is correct. We'll look into a solution
for Phusion Passenger 3.
But for Rails 3 specifically, it can use whatever bundled Rack version
it wants; in Phusion Passenger 2.2.9 we fixed the Rails loader to be
Rails 3 compatible, and the Rails loader does not 'require rack'.
> and it can be fixed with Passenger + Bundler as the particular rack version
> can be bundled up and used by Passenger when needed to spawn a rack app?
That is one of the possible solutions.
> Also, In Passenger 2.2.8 Rack has been unvendored? So, is it loaded from
> gems now?
This is correct.
With kind regards,
Hongli Lai
and it can be fixed with Passenger + Bundler as the particular rack version can be bundled up and used by Passenger when needed to spawn a rack app?
Also, In Passenger 2.2.8 Rack has been unvendored? So, is it loaded from gems now?
Also, In Passenger 2.2.8 Rack has been unvendored? So, is it loaded from gems now?Yes.
--
You received this message because you are subscribed to the Google Groups "Phusion Passenger Discussions" group.
To post to this group, send email to phusion-...@googlegroups.com.
To unsubscribe from this group, send email to phusion-passen...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/phusion-passenger?hl=en.
I can see why you would like to go for Scenario C. Correct me if I am wrong:
- config directive not detected.
- Load from rubygems as a default.
- require "rack"
- parse "config.ru"