From aeb2a0e3e7619f89acf087e28be87953e66f2890 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Sun, 17 Jun 2007 14:15:26 -0700 Subject: [PATCH] added more to site docs --- examples/gravatar.god | 18 ++++++++- site/images/bullet.jpg | Bin 12942 -> 29283 bytes site/images/god_logo1.gif | Bin 1419 -> 1419 bytes site/index.html | 100 +++++++++++++++++++++++++++++++++++++++++++--- test/test_watch.rb | 1 + 5 files changed, 112 insertions(+), 7 deletions(-) diff --git a/examples/gravatar.god b/examples/gravatar.god index 3f9511d..0d7492d 100644 --- a/examples/gravatar.god +++ b/examples/gravatar.god @@ -12,10 +12,26 @@ God.meddle do |god| w.cwd = RAILS_ROOT w.start = "mongrel_rails cluster::start --only #{port}" w.stop = "mongrel_rails cluster::stop --only #{port}" + + pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid") w.start_if do |start| start.condition(:process_not_running) do |c| - c.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid") + 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 diff --git a/site/images/bullet.jpg b/site/images/bullet.jpg index a67016513e2a9d5956b3791cec21f8abb04676f3..baadeeb19e4a53a127507eff4a9dee2c83003729 100644 GIT binary patch literal 29283 zcwX&231Ab|ws*2NX}Y8vJ4{1qS&}A`J)sM2+R{QxOE(r#NRw$BnvG;a%c87;EV7Bn zrUD`e_&`Ax5fv(m3bHAnBEAA5AgDzxsG$9KCP|x?7Kl&%@B4E~PR>2|Ecc#sX6_`p zGcxfW#wc6goc1@_y-!#(|^dUF_i<5mk0U+0D=G;i2!s+A@C0%odJ`g0VqSd zG|^*`-X0kmL>P&I3BDYNl%k{H>+Eb3V0h%~;agY0y)zYngmCYBn$cE4Q4DF3c5+yZKiA0G>C2I5`FO^t^6Z%9Y9$i*4>h<5TX}hZ z)Pj~d^j1UV!+lURPj4_;Nz(vosI(HL7E_^^Oe@uBB^o#;`WmEpo@;1LV+~$IZ=(6Y z4J?H2k!AVD1R2{L6U5;g6Bu8Q4P+v%$u`aIv6t-;R5(f|LV;(>bT~N% zlf@3=aD$Q7oiJu}Z)Z3_7zmxlpfTC3ASRtBgPnXjBQ^qKrVZ6c3dT*7vZ5BReKoyj zTy)`qGMU^l{e+I)Ye`Z4`5OkOB4*w88SxoU6&o{aUm%nnPL^E2f7mheosV4?f6Pi) zy8iLko<8`=S3kYD^W9UI8cNH@&sw%&*L$bGzNs2GtfG4MGaGjwI&=9JAJAxUv*v@m;<_&(o z2d=P(J^JC-U%t5G*~bp|IQzxA1(TM}=KQoMa7yE6jo-%envXhJq6DbZbMhDrDiiFkWc9*7ir0(cg=g`8m=nLJ^z&C%BWqvT zxTu=!qkltob$cZ#wZ>vb$KwvC$!1L!V2Kg|idzjfqsdy4EGQ|?5~&5LDcq#kjC@`3 zh=NSiZZmV6%{dPH}<5X2%`Ggj{G<1QimEgi!$fx!trF7vvgE1|o&aNvgsp zq(BoMV|E8TQzRDXEAT9v!=i^|Ubf9)nrO2UdUGM}OcImwP|c&>wmxApRN+LT!GY@u zo5QQaNpcdfyP~x?WLfl9=n_hLB<^F_MBtV*heJQ1*|eT)l2r51+Ocu}$&s3H=;joa zG)YVm?OXFs)ojA8gs%aA=6Y}27Mn3cPvE}Bjj)|Up3FrOr3h0MV;U`aK39)S5>s9G zwdo|FSe98|;cFH4<8Wjtk|eR0qyj2#O19V=<|f|#L!9p*L!&2P@%_`Pr;Vxk#t~~7 z$3Ox7u>vYG=*@7R|Fq(1H7$orRc~!d5+%OXc^|e)CU1+aP$^rmn={<*pxdi>KjZ3e%|Bq# z`(5?zmc38i`-a8mXz(MY@F@6yQM#??*~+Z9>_nKlt!iwCtx~mJyBc|*cK_Vkh3U(I z=W3WziXNi3;D1rcCfY5D1vV#9WN?`5#NSx9_nM;5aIJcg87Bz8692$ub&tva@zRos z$m+t1F_l)X(aMy6R%zY!!TmoitrDyL?^)6R3u^2hb8Tgo6Ij;&kDMBPbNbh=>;Gj1 z99Z1{5fyB=8~;Bn@a;|0XUHW*Xl`JU|I-$EkEgVPoKpAiYt5zQnY=`jD3v_u*F3N> z9*#NJW~gd5RIWEWaq<0Bi3xW6F6Zr*N-?G6Gpu`myV346+nc4IlWd;jgHEyi8G1jY zwVtAPhDl=T2hkKR_1o>Y?%#Di`w$TCJN27yJk=Kpnjm#5aQ_+{LN&?XiEF5Kr>1sy z%Ic3)o8#3(+*({ugK8y&Q!Os={_;4eSVX;Z@}tf=(%Q`2#pO$OXqYR+|%_FMR2Qhkt!fG;-H z$jR`r&8~3RT=o_$md#uCzUUp0I;Iayx z&1`e{1efntNFUhLK@MYx%}Ty=2%A0MML2Qaz;Vqmkaux;Wi|o^^e%odOmSsvaq4L5 z?bd@YB()wi^P?z|Od)l~VUQAlHXpb{cEZT}NT5Imihv9>t;g2Ly8R(s|*?=wco2oTVt_Xa6*sPSj<+ZwkBCX8P`IZWQzqTB|=ms3*0+FhvyZb zI-3JW<%yWcAd#w2EK#bI$)zeGn&mK|8MpzJxc7gem_&;y;6FhM7e&z|hp}8+n33gi z1zX9!JI1PIi8e=t7}IDpVu@5Nm5QK*$T`7E=xan)XHT~gubm9sNnOap>phfg>*10> zBnt!{88^5c;WegaPc5QH_E6z#vQ3&NxmxO!SOi0glNaNyS*@iDOf|T9c!tS>TgfZX z6wIsBx}#0S5k874U&RsaD-O{Urtx@&sRDn8WPLk$T5vtL186@RTNfJn3U0I zC>ae#VJU@W6qZw%(j`YCm0(JtL3ZYV{5~_t7Aq)+M2{EY}2n!w#PA2Iu&&ZN0B~lnjnN*djQK~cLm_j4LuuO?cAydda z8Eugv3U?Npy4q*kr z%2LQMNJBoXP${esnFQ7}OuP)!2o!xDMYdsm!zv+<8)^S6S!O2G z)+r?tg$~P9WM!%_rBb7V)u2

2#if|D|;R*Mqjpz`Ibir~=5;>c}sU@C?rv8VZp_ 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 diff --git a/site/index.html b/site/index.html index c90c9ab..40709bb 100644 --- a/site/index.html +++ b/site/index.html @@ -145,15 +145,18 @@ ul.features li { pre { - font-size: 1.2em; line-height: 1.5; border: 1px solid #ccc; padding: 1em; background-color: #efefef; + margin: 1em 0; +} + +code { + font-size: 1.2em; } .ruby .keywords { - font-weight: bold; color: blue; } @@ -218,7 +221,9 @@ pre {

Finally, a Config File that Makes Sense

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:

-
# This is the actual config file used to keep the mongrels of
+
# file: gravatar.god
+# 
+# This is the actual config file used to keep the mongrels of
 # gravatar.com running.
 
 RAILS_ROOT = "/var/www/gravatar2/current"
@@ -232,16 +237,99 @@ God.meddle do |god|
       w.cwd = RAILS_ROOT
       w.start = "mongrel_rails cluster::start --only #{port}"
       w.stop = "mongrel_rails cluster::stop --only #{port}"
+      
+      pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
 
       w.start_if do |start|
         start.condition(:process_not_running) do |c|
-          c.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
+          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
-
+end
+ +

That's a lot to take in at once, so I'll break it down by section and explain what's going on in each.

+ +
RAILS_ROOT = "/var/www/gravatar2/current"
+ +

Here I've set a constant that is used throughout the file. Keeping the RAILS_ROOT value in a constant makes it easy to adapt this script to other applications. Because the config file is Ruby code, I can set whatever variables or constants I want that make the configuration more concise and easier to work with.

+ +
God.meddle do |god|
+  god.interval = 30 # seconds
+
+  ...
+end
+ +

The meat of the config file is defined inside a God.meddle block. At this level, you set system wide settings like interval. In this case, we've specified that god should do a check every 30 seconds.

+ +
  %w{8200 8201 8202}.each do |port|
+    ...
+  end
+ +

Because the config file is written in actual Ruby code, we can construct loops and do other intelligent things that are impossible in your every day, run of the mill config file. I need to watch three mongrels, so I simply loop over their port numbers, eliminating duplication and making my life a whole lot easier.

+ +
    god.watch do |w|
+      w.name = "gravatar2-mongrel-#{port}"
+      w.cwd = RAILS_ROOT
+      w.start = "mongrel_rails cluster::start --only #{port}"
+      w.stop = "mongrel_rails cluster::stop --only #{port}"
+      
+      ...
+    end
+ +

A watch represents a single process or task that has concrete start, stop, (and possibly restart) operations. You can define as many watches as you like inside the God.meddle block. In the example above, I've got a Rails instance running in a Mongrel that I need to keep alive. Every watch must have a unique name so that it can be identified later on. The optional cwd attribute tells god to switch to that directory before executing any commands. The start and stop attributes specify the commands to start and stop the process. If no restart attribute is set, restart will be represented by a call to stop followed by a call to start.

+ +
      pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
+ +

Another variable to hold the location of the PID file.

+ +
      w.start_if do |start|
+        start.condition(:process_not_running) do |c|
+          c.pid_file = pid_file
+        end
+      end
+ +

Watches contain conditions grouped by the action to execute should they fail. I start with a start_if block that contains a single condition. Conditions are specified by calling condition with an identifier, in this case +:process_not_running. This condition checks to see if the process corresponding to the PID found in the pid_file is currently running. If it's not, the condition will fail causing a start command to be issued. The process_not_running condition will take care of cleaning up orphaned PID files by default, so we don't have to worry about it. We could turn that behavior off by adding c.clean = false. + +

      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
+      
+        ...
+      end
+ +

Similar to start_if there is a restart_if command that groups conditions that should trigger a restart. The memory_usage condition will fail if the specified process is using too much memory. Once again, the pid_file must be set. The maximum allowable amount of memory is specified with the above attribute in units of kilobytes. The number of times the test needs to fail in order to trigger a restart is set with times. This can be either an integer or an array. An integer means it must fail that many times in a row while an array [x, y] means it must fail x times out of the last y tests.

+ +
      w.restart_if do |restart|
+        ...
+      
+        restart.condition(:cpu_usage) do |c|
+          c.pid_file = pid_file
+          c.above = 50 # percent
+          c.times = 5
+        end
+      end
+ +