views:

175

answers:

1

One thing I really don't understand is how I can pass custom start-up options to a mongrel instance.

I see that a common approach is the use environment variables, but in my environment this is not going to work because my rails application serves many different clients. Much code is shared between clients, but there are also many differences which I implement by subclassing controllers and views to overload or extend existing features or introduce new ones. To make this all work, I simply add the paths to client specific modules the module load path ($:).

In order to start the application for a particular client, I could now use an environment variable like say, TARGET=AMAZONE. Unfortunately, on some systems I'm running multiple mongrel clusters, each cluster serving a different client. Some of these systems run under Windows and to start mongrel I installed mongrel_services. Clearly, this makes my environment variable unsuitable.

Passing this extra bit of data to the application is proving to be a real challenge. For a start, mongrel_rails service_install will reject any [custom] command line parameters that aren't documented. I'm not too concerned as installing the services using the install program is trivial.

However, even if I manage to install mongrel_services such that when run it passes the custom command line option --target to mongrel_rails start, I get an error because mongrel_rails doesn't recognize the switch.

So here were the things I looked at:

  1. Pass an extra parameter:

    mongrel_rails start --target XYZ ...

  2. use a config file and add target:XYZ, then do:

    mongrel_rails start -C x:\myapp\myconfig.yml

  3. modify the file:

    Ruby\lib\ruby\gems\1.8\gems\mongrel-1.1.5-x86-mswin32-60\lib\mongrel\command.rb

  4. Perhaps I can use the --script option, but all docs that I found on it were for Unix

1 and 2 simply don't work. I played with 4 but never managed it to do anything. So I had no choice but to go with 3. While it is relatively simple, I hate changing ruby library code.

Particularly disappointing is that 2 doesn't work. I mean what is so unreasonable about adding other [custom] options in the config file? Actually I think this is a fundamental piece that is missing in rails. Somehow, the application should be able to register and access command line arguments it expects.

If anybody has a good idea how to do this more elegantly using the current infrastructure, I have a chocolate fish to give away!!!

A: 

It may not be necessary to pass in something to mongrel. It may be possible to use an existing mechanism that will provide the flexibility you seek. Let's start by trying to be very clear about the constraints.

To paraphrase, it seems that the following conditions are in effect.

  • The same code base (or very similar code base) is used to serve multiple customers
  • Identifiers that influence application execution are needed at application startup (or before execution) to define application behavior
  • Multiple sets of mongrel clusters can be used on a single system with each cluster dedicated to a single client
    • This implies that a cluster of processes are all serving the same code base with the same configuration value(s)
  • Some customers wish to run on Windows servers, which obviates the use of some Unix style environment and scripting behavior.

One assumption that should be validated is that each code base is in a separate directory. If so, then there may be a very straightforward solution.

If each customer is in its own directory, like so:

/src
  /customer1
  /customer2
  /customer3

And if you start your mongrel processes with something like:

[/src/customer1]$ mongrel_rails cluster::start

Then, you could have a customer_config.yml file that is read at system startup (in your environment.rb) in which you can place your client customization value. So, if you need to pass in "Amazone" as the target value, then your yaml file might look like:

target:
  Amazone

Then, each customer gets their own customer_config.yml file, which resides only in their directory, and you have only one file to change to switch behaviors when adding a new customer.

Modifying your environment.rb to look for a specifically named YAML file would be perfectly acceptable. It's rather easy to parse a YAML file, and it gives a lot of flexibility for managing customization by each customer.

Peter Degen-Portnoy
All your assumptions are correct except that not "each customer is in its own directory".Our structure looks more like:root/app/controllers/fooroot/app/controllers/foo/Amazoneroot/app/controllers/foo/Nileroot/app/controllers/foo/Kongoroot/app/views/fooroot/app/views/foo/Amazoneroot/app/views/foo/Nileroot/app/views/foo/Kongoroot/configroot/config/Amazoneroot/config/Nileroot/config/Kongoroot/logroot/log/Amazoneroot/log/Nileroot/log/Kongoetc.Customer specific folders (i.e. Amazone, Nile, Kongo) only exist if a client does require custom specific behavior.
whaka
The important thing is that if you start the rails application for say Nile, none of the files residing in Amazone or Kongo have any relevance and the system would work all the same for Nile if you deleted any folders with Amazone or Kongo in the path.Clearly, we need something that is being passed to the startup code so it can determine which implementation to activate. I couldn't care less, if this happens via the content of a YAML file (e.g. -C switch), a custom command line switch or the --script parameter.
whaka
Thanks for the clarification. The solution may be stretching the Rails convention a bit far; I've found that when it's hard in ROR generally means I've strayed too far from convention. How is traffic directed to the application? How does a visitor who wishes to visit the Amazone site get there as opposed to the Kongo or Nile site?
Peter Degen-Portnoy