Lazy Mixin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# Before you ask--yes, this has a very specific use case and is not # generally applicable to the problem of fine-grained lazy evaluation. # But it does *exactly* what I need it to do. =) # Allows attributes to be declared as lazy, meaning that they won't be # computed until they are asked for. Just mix this module in: # # class Foo # include Lazy # ... # end # # To specify a lazy reader: # # lazy_reader :att # # Then, define a method called __bake__ that computes all your lazy # attributes: # # def __bake__ # @att = ... # end # # That's it! (Tom Preston-Werner: rubyisawesome.com) module Lazy module ClassMethods def lazy_reader(*args) args.each do |arg| define_method(arg) do self.__prebake__ instance_variable_get(('@' + arg.to_s).intern) end end end end def __prebake__ return if @__baked__ self.__bake__ @__baked__ = true end def self.included(base) base.extend(ClassMethods) end end # A pedagogical class with a lazy attribute class Foo include Lazy attr_reader :id lazy_reader :body def initialize(id) @id = id end def __bake__ puts "__baking__" @body = "The 30th fibonacci is #{self.fib(30)}" end def fib(n) return 1 if n == 0 || n == 1 return fib(n-1) + fib(n-2) end end t = Foo.new('abc') puts t.id # => (immediate) "abc" puts t.body # => (short pause) The 30th fibonacci is 1346269 puts t.body # => (immediate) The 30th fibonacci is 1346269 |
Hash Defaults and Path of Madness
This is a little story about innocent Ruby mistakes and how they can ruin your day. One of our interns here are Powerset had some code that used default hash values.
1 2 |
h = {}
h.default = [] |
Fair enough. Then the code did this:
h[:foo] << 'foo' # => ["foo"] |
Which happily returns in exactly the expected fashion. We can even check the value to make sure:
h[:foo] # => ["foo"] |
But then later on we look more closely at the hash and WTF it's empty!
h # => {} |
Madness! Until you realize that a hash's default value is only used as the return value for a hash lookup of a non-existent key.
1 2 |
h.default # => ["foo"] h[nil] # => ["foo"] |
And then you can only laugh once you look back at the code that seemed to work and see exactly why it was so deceiving.
god 0.4.0 released
Progress on god is moving along as quick as ever. This release adds a bunch of new features and bug fixes. Most interestingly you'll find several useful new command line functions:
god statusprints out the status of each Watchgod logshows realtime logs for a specific Watch (even if you don't have god logging to file)god loadloads or reloads a config file into a running god instancegod terminatestops all Watches and then stops god (useful when testing your setup)
The logging system has been beefed up with proper timestamps and criticality levels. Log messages are more complete overall. You can also get the STDOUT/STDERR of a god-daemonized process written to a log file by specify 'w.log =
If you let god daemonize your process for you, there's no need to provide a stop command. A default killing lambda will take care of gracefully (or not so gracefully if necessary) stopping your god-daemonized process.
The validity of your config file is checked better than previous versions to point you to the problem area of your config.
The bug that prevented group control from working has been fixed so you can now start/stop/etc groups of Watches.
Updated documentation is now available on the website:
WHAT IS GOD?
God is an easy to configure, easy to extend monitoring framework written in Ruby.
Keeping your server processes and tasks running should be a simple part of your deployment process. God aims to be the simplest, most powerful monitoring application available.
DISCLAIMER
God is still very young, I'd love to get feedback and bug reports, but I do not yet recommend you use it for mission critical tasks. I personally use it in production but then I'm a daring fellow.
INSTALL
sudo gem install god
FEATURES
- Config file is written in Ruby
- Easily write your own custom conditions in Ruby
- Supports both poll and event based conditions
- Different poll conditions can have different intervals
- Easily control non-daemonized processes
EXAMPLE
The easiest way to understand how god will make your life better is by looking at a sample config file. The following configuration file is what I use at gravatar.com to keep the mongrels running:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# file: gravatar.god # run with: god -c /path/to/gravatar.god # # This is the actual config file used to keep the mongrels of # gravatar.com running. RAILS_ROOT = "/var/www/gravatar2/current" %w{8200 8201 8202}.each do |port| God.watch do |w| w.name = "gravatar2-mongrel-#{port}" w.interval = 30.seconds # default w.start = "mongrel_rails cluster::start --only #{port} \ -C #{RAILS_ROOT}/config/mongrel_cluster.yml" w.stop = "mongrel_rails cluster::stop --only #{port} \ -C #{RAILS_ROOT}/config/mongrel_cluster.yml" w.grace = 10.seconds w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid") w.behavior(:clean_pid_file) w.start_if do |start| start.condition(:process_running) do |c| c.interval = 5.seconds c.running = false end end w.restart_if do |restart| restart.condition(:memory_usage) do |c| c.above = 150.megabytes c.times = [3, 5] # 3 out of 5 intervals end restart.condition(:cpu_usage) do |c| c.above = 50.percent c.times = 5 end end end end |
DOCS
Detailed documentation is available at http://god.rubyforge.org/
CHANGES
== 0.4.0 / 2007-09-13
- Major Enhancements
- Add the ability for conditions to override transition state (for exceptional cases)
- Implement dynamic load of config files while god is running (god load
) - Add ability to save auto-daemonized process output to a log file
- Add robust default stop lambda command for auto-daemonized processes (inspired by _eric)
- Add status command for god binary (shows status of each watch)
- Create proper logger with timestamps
- Add log command to god binary to get real time logs for a specific watch from a running god instance
- Add terminate command for god binary (stop god and all watches)
- Minor Enhancements
- Enforce validity of Watches
- Enforce that God.init is not called after a Watch
- Move pidfiledirectory creation and validation to God.start
- Remove check for at least one Watch during startup (now that dynamic loading exists)
- New Conditions
- Tries < PollCondition - triggers after the specified number of tries
- Add :notifywhenflapping behavior to check for oscillation [kevinclark]
- Add :degrading_lambda condition. [kevinclark] It uses a decaying interval (1/2 rate) for 3 cycles before failing.
- Bug Fixes
- Use exit!(0) instead of exit! in god binary to exit with code 0 (instead of default -1)
- Command line group control fixed
- Fix cross-thread return problem
AUTHORS
Tom Preston-Werner Kevin Clark
Powerset Interview
I was recently interviewed by my buddy Ryan Ferrier as part of a series of Powerset employee interviews for Steve Newcomb's blog. I know you think interviews are boring, so here's a little taste of mine to dispel any myths:
Rumor has it that you listen almost exclusively to techno music, is this true?
My dream is to code in a large, white, egg-shaped room wherein a large, omnidirectional speaker system is suspended at one locus, and an elaborate, 9 screen, multi-platform computing setup is suspended at the other locus. In this dream, I am sitting comfortably at the computer locus while thundering trance emanating from the opposite locus is parabolically focused upon my exact location. Then I could get some *real* coding done.
Rumor also has it that when listening to said techno music, you get in a trance-like state for hours on end and transform into a coding machine. Could you describe this altered state of being for us?
Remember the guys from "The Matrix" that could look at those screens of waterfalling green glyphs and see real world objects in them? It's nothing like that. That's impossible and ridiculous. If you've ever sat zazen and meditated on some ancient koans, that would be another good example of what it's not like. It's also not like watching your dog eat peanut butter. I'd keep going but it would take infinitely long to describe everything that it's not, so I'll have to stop and leave you mystified by the enigma of it all.
Continue reading the full Tom Preston-Werner Interview.
god 0.3.0 released
Plenty of big changes and improvements in this release of god. Most noticeable is a simplification of the config file. Sadly, we must say goodbye to the much loved God.meddle and promote God.watch to top level. This change allows you to easily load in other god config files and have them work as expected. There's even a God.load that takes a glob-style file path string and expands it to load multiple files.
PID file support is now baked in so you don't have to set the pid_file attribute on conditions anymore. This also allows god to support processes that aren't already daemons. If you don't specify a PID file for the watch, god will auto-daemonize and keep track of your process for you! To use this feature, you must either run as root (pid files will be stored by default in /var/run/god) or set the pid_file_directory attribute in a God.init block (see docs).
For anyone that had problems installing the 0.2.0 release because of the events system not compiling, god 0.3.0 will now allow you to install without event support. Most systems are capable of supporting events, but it requires some dedication to get the headers in place and make sure your kernel is new enough. To determine if your god installation has event support you can run "sudo god -V" (this MUST be run as root on Linux, as netlink connector requires root permissions).
Using the god binary you can now control your watches from the command line. You can start/stop/restart/monitor/unmonitor watches at your demand.
New watch attributes now available: pid_file: sets the watch process' PID file location uid/gid: start processes as someone else (requires root access) group: assign a watch to a group (to control them all at once) autostart: prevent auto start on god start if false
Updated documentation is now available on the website:
WHAT IS GOD?
God is an easy to configure, easy to extend monitoring framework written in Ruby.
Keeping your server processes and tasks running should be a simple part of your deployment process. God aims to be the simplest, most powerful monitoring application available.
DISCLAIMER
God is still very young, I'd love to get feedback and bug reports, but I do not yet recommend you use it for mission critical tasks. I personally use it in production but then I'm a daring fellow.
INSTALL
sudo gem install god
FEATURES
- Config file is written in Ruby
- Easily write your own custom conditions in Ruby
- Supports both poll and event based conditions
- Different poll conditions can have different intervals
- Easily control non-daemonized processes
EXAMPLE
The easiest way to understand how god will make your life better is by looking at a sample config file. The following configuration file is what I use at gravatar.com to keep the mongrels running:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# file: gravatar.god # run with: god -c /path/to/gravatar.god # # This is the actual config file used to keep the mongrels of # gravatar.com running. RAILS_ROOT = "/var/www/gravatar2/current" %w{8200 8201 8202}.each do |port| God.watch do |w| w.name = "gravatar2-mongrel-#{port}" w.interval = 30.seconds # default w.start = "mongrel_rails cluster::start --only #{port} \ -C #{RAILS_ROOT}/config/mongrel_cluster.yml" w.stop = "mongrel_rails cluster::stop --only #{port} \ -C #{RAILS_ROOT}/config/mongrel_cluster.yml" w.grace = 10.seconds w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid") w.behavior(:clean_pid_file) w.start_if do |start| start.condition(:process_running) do |c| c.interval = 5.seconds c.running = false end end w.restart_if do |restart| restart.condition(:memory_usage) do |c| c.above = 150.megabytes c.times = [3, 5] # 3 out of 5 intervals end restart.condition(:cpu_usage) do |c| c.above = 50.percent c.times = 5 end end end end |
DOCS
Detailed documentation is available at http://god.rubyforge.org/
CHANGES
== 0.3.0 / 2007-08-17
- Fix netlink header problem on Ubuntu Edgy [Dan Sully]
- Add uid/gid setting for processes [kevinclark]
- Add autostart flag for watches so they don't necessarily startup with god [kevinclark]
- Change command line call options for god binary to accommodate watch start/stop functionality
- Add individual start/stop/restart grace periods for finer grained control
- Change default DRb port to 17165 ('god'.to_i(32))
- Implement command line control to start/restart/stop/monitor/unmonitor watches/groups by name
- Watches can now belong to a group that can be controlled as a whole
- Allow god to be installed (sans events) on systems that don't support events
- Daemonize and handle PID files for non-daemonizing scripts [kevinclark]
- Fix simple mode lifecycle gap
- Remove necessity to specify pid_file for conditions
- Change config file to use God.init and God.watch directly instead of God.meddle block
- Move god binary command logic to main library
- Enhance god binary with better reporting
- Fix synchronization bug in Timer (reported by Srini Panguluri)
- Add Lambda condition for easy custom conditions [Mike Mintz]
- Add sugar for numerics (seconds, minutes, kilobytes, megabytes, percent, etc)
- Add optional PID and log file generation to god binary for daemon mode
- Add God.load to do glob enabled loading
- Add -V option to god binary for detailed version/build info
AUTHORS
Tom Preston-Werner
Kevin Clark
god 0.2.0 released
A lot of work has gone into god since the last release. Say goodbye to polling for process status--support for event based conditions via kqueue/netlink has been added (thanks Kevin Clark)! Only a few events are currently supported (most prominently process exit), but the way is now open for the addition of other events. A new, advanced syntax is available (in addition to the familiar simple syntax) that gives you full power over the new state based lifecycle of your Watches. Updated documentation is available on the website:
WHAT IS GOD?
God is an easy to configure, easy to extend monitoring framework written in Ruby.
Keeping your server processes and tasks running should be a simple part of your deployment process. God aims to be the simplest, most powerful monitoring application available.
DISCLAIMER
God is still very young, I'd love to get feedback and bug reports, but I do not yet recommend you use it for mission critical tasks. I personally use it in production but then I'm a daring fellow.
INSTALL
sudo gem install god
- note: currently tested only on Redhat Linux and Darwin (won't work on Windows)
FEATURES
- Config file is written in Ruby
- Easily write your own custom conditions in Ruby
- Supports both poll and event based conditions
- Different poll conditions can have different intervals
EXAMPLE
The easiest way to understand how god will make your life better is by looking at a sample config file. The following configuration file is what I use at gravatar.com to keep the mongrels running:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# file: gravatar.god # run with: god start -c /path/to/gravatar.god # # This is the actual config file used to keep the mongrels of # gravatar.com running. RAILS_ROOT = "/var/www/gravatar2/current" God.meddle do |god| %w{8200 8201 8202}.each do |port| god.watch do |w| w.name = "gravatar2-mongrel-#{port}" w.interval = 30 # seconds default w.start = "mongrel_rails cluster::start --only #{port} \ -C #{RAILS_ROOT}/config/mongrel_cluster.yml" w.stop = "mongrel_rails cluster::stop --only #{port} \ -C #{RAILS_ROOT}/config/mongrel_cluster.yml" w.grace = 10 # seconds pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid") w.behavior(:clean_pid_file) do |b| b.pid_file = pid_file end w.start_if do |start| start.condition(:process_running) do |c| c.interval = 5 # seconds c.running = false c.pid_file = pid_file end end w.restart_if do |restart| restart.condition(:memory_usage) do |c| c.pid_file = pid_file c.above = (150 * 1024) # 150mb c.times = [3, 5] # 3 out of 5 intervals end restart.condition(:cpu_usage) do |c| c.pid_file = pid_file c.above = 50 # percent c.times = 5 end end end end end |
DOCS
Detailed documentation is available at http://god.rubyforge.org/
CHANGES
== 0.2.0 / 2007-07-18
- Rewrote innards to use a state and event based lifecycle
- Basic support for events via kqueue (bsd/darwin) and netlink/pec (linux) [kevinclark]
- Added advanced syntax (simple syntax calls advanced api underneath)
- Condition returns have changed meaning. With simple syntax, a true return activates block
- Updated http://god.rubyforge.org with updated simple config and new advanced config
AUTHORS
Tom Preston-Werner
Kevin Clark
MySQL secrets: \G instead of ;
I'm a MySQL command line junkie. Even when I have a GUI frontend installed, I always find myself typing mysql into terminal when I need to peek inside the database. As such, one trick that has changed my life for the better is the \G statement terminator. Normally when you execute a query you get something like:
1 2 3 4 5 6 7 |
mysql> select * from queries order by id desc limit 1; +-----+------------------------------------+--------------+------------+------------+ | id | query | query_set_id | created_at | updated_at | +-----+------------------------------------+--------------+------------+------------+ | 969 | when a stranger calls sound boards | 103 | 2007-07-09 | 2007-07-09 | +-----+------------------------------------+--------------+------------+------------+ 1 row in set (0.00 sec) |
That's ok, but for tables with more than a few columns you get a nasty bunch of badly wrapped output that's essentially impossible to decipher. If you replace the terminating semicolon with \G, you'll get this output instead:
1 2 3 4 5 6 7 8 |
mysql> select * from queries order by id desc limit 1 \G
*************************** 1. row ***************************
id: 969
query: when a stranger calls sound boards
query_set_id: 103
created_at: 2007-07-09
updated_at: 2007-07-09
1 row in set (0.00 sec)
|
Aaaaaaaaah! Now we're talking. You can even copy this output and paste it right into a YAML fixture in your rails app (with a little fixing of the indentation)!
Welcome!
You're reading the weblog of Ruby hacker Tom Preston-Werner (aka mojombo).

- Employer:
- Powerset
- Location:
- San Francisco
- Disposition:
- Awesome
