Manana

Manana lets you defer the initialization of an object until its methods are called.

This can be useful in cases where initialization may take a long time or fail due to errors. For example, in rails, if the database specified in database.yml doesn't exist at start time, the rails application will fail initialization. Likewise if you tie configuration of SOAP services (e.g. using Savon) to your application initialization, and the service wsdl isn't up, your application will fail to start.

Instead, it is an established best practice in service-oriented architectures to make your application or service startup order independent: i.e. your app starts fast and initializes other dependencies afterwards, providing fault detection and self-healing properties for the app.

Manana is a simple approach that allows you to keep your configuration and initialization code in the same place, while deferring it to method calls.

Pros

  • Reduces the startup time for your app. (i.e. moves the startup cost from initialization to first use)

  • Once initialization is succesful, it stores the object instance for reuse.

  • Until the initialization is successful, it will retry every time a method is called.

  • You can layer more complex retry semantics such as exponential backoff using this wrapper. See samples/exponential_backoff.rb

Cons

  • If your initialization takes a very long time, (i.e. a cache) you may want to pre-warm it instead of taking the hit on the first use of the object.

  • Very simple approach. You may want more complex retry semantics, or pooling.

Similar ideas:

Installation

Add this line to your application's Gemfile:

gem 'manana'

And then execute:

$ bundle

Or install it yourself as:

$ gem install manana

Usage

require 'manana'

# initialization...
client = Manana.deferred_init {
  Weather.setup    # web service adapter setup
  Weather          # return the class instance
}

runtime_loop {
  #   wait for next interval
  weather = client.city_weather("02201")    # deferred initialization happens here once
  puts "At %s the temperature is currently %s F and the humidity is %s." % [weather.city, weather.temperature, weather.relative_humidity]
}

See the samples for more detailed examples of use.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request