<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Mad Marmot: Running ar_sendmail with monit</title>
    <link>http://www.lukeludwig.com/blog/articles/2007/12/05/running-ar_sendmail-with-monit</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>A blog about programming, ruby, rails, and my crazy outdoor pursuits</description>
    <item>
      <title>Running ar_sendmail with monit</title>
      <description>&lt;p&gt;Sending email from a web application, especially blast emails to a lot of people, can take a lot of time. Generally you don&amp;#39;t want the user to wait until all the emails have been handed off to the smtp server. You also probably don&amp;#39;t want to tie up an entire mongrel with sending mail. The &lt;a href="http://blog.segment7.net/articles/2006/08/15/ar_mailer"&gt;ar_mailer gem&lt;/a&gt; solves this problem in excellent fashion, by saving pending emails to the database and having a separate ruby daemon process periodically check the database and send emails. I recently set up one of our rails apps at &lt;a href="http://teamsporttech.com"&gt;work&lt;/a&gt; to use ar_mailer. Configuring it to use ar_mailer was incredibly easy, but it was tricky to get the ar_sendmail ruby daemon process to run under &lt;a href="http://www.tildeslash.com/monit/"&gt;monit&lt;/a&gt;. On our production servers which we have hosted at &lt;a href="http://engineyard.com/"&gt;Engine Yard&lt;/a&gt;, we want every process that our application depends on to be monitored by monit.&amp;nbsp;&lt;/p&gt;&lt;p&gt;The primary feature that ar_sendmail lacks to play nice with monit is the ability to leave a pid file after it starts up and to remove it when the process exits. This has already been pointed out on &lt;a href="http://rubyforge.org/tracker/index.php?func=detail&amp;amp;aid=14839&amp;amp;group_id=1513&amp;amp;atid=5924"&gt;rubyforge as a feature request&lt;/a&gt;. Here is what I did to get ar_sendmail working under monit: (ar_mailer 1.3.1) &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0) Find the file ar_sendmail.rb on your system and open it for editing.&lt;/strong&gt; &lt;/p&gt;&lt;p&gt;For me this was at /usr/local/lib/ruby/gems/1.8/gems/ar_mailer-1.3.1/lib/action_mailer/.&amp;nbsp; Another common location is /usr/lib/ruby/gems/1.8/gems/ar_mailer-1.3.1/lib/action_mailer/ &lt;/p&gt;&lt;p&gt;&lt;strong&gt;1) Create a class variable to store the pid file path in and a method to remove the pid file.&lt;/strong&gt; &lt;/p&gt;&lt;p&gt;I put this just below &amp;quot;attr_accessor :failed_auth_count&amp;quot; &lt;/p&gt;&lt;pre&gt;  @@pid_file = nil&lt;/pre&gt;&lt;pre&gt;  def self.remove_pid_file&lt;br /&gt;    FileUtils.rm(@@pid_file) if @@pid_file&lt;br /&gt;  end  &amp;nbsp;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;2) Modify the self.run method in ar_sendmail.rb to create a pid file, and to not start up if an ar_sendmail process is already running&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if options[:Daemon] then &lt;br /&gt;      require &amp;#39;webrick/server&amp;#39;       &lt;br /&gt;      @@pid_file = &amp;quot;#{options[:Chdir]}/log/ar_mailer.pid&amp;quot;            &lt;br /&gt;      if File.exists? @@pid_file             &lt;br /&gt;        # check to see if process is actually running&lt;br /&gt;        pid = &amp;#39;&amp;#39;&lt;br /&gt;        File.open(@@pid_file, &amp;#39;r&amp;#39;) {|f| pid = f.read.chomp }             &lt;br /&gt;        if &lt;span style="padding: 0pt; background-color: yellow; color: black; display: inline; font-size: inherit"&gt;system&lt;/span&gt;(&amp;quot;ps -p #{pid} | grep #{pid}&amp;quot;) # returns true if process is running, o.w. false&lt;br /&gt;          $stderr.puts &amp;quot;Warning: The pid file #{@@pid_file} exists and ar_sendmail is running. Shutting down.&amp;quot;         &lt;br /&gt;          exit&lt;br /&gt;        else&lt;br /&gt;          # not running, so remove existing pid file and continue&lt;br /&gt;          self.remove_pid_file&lt;br /&gt;          log &amp;quot;ar_sendmail is not running. Removing existing pid file and starting up...&amp;quot;          &lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;      WEBrick::Daemon.start  &lt;br /&gt;      File.open(@@pid_file, &amp;#39;w&amp;#39;) {|f| f.write(&amp;quot;#{Process.pid}\n&amp;quot;)}    &lt;br /&gt;    end                &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If the pid file already exists, this code will check to see if the process is actually running.&amp;nbsp; If it is then it will exit, otherwise it will remove the file and continue. This is useful for when the process dies ungracefully somehow (server crashes, killed with -9, .etc), in which case it will leave a pid file behind. Note that this differs from the code suggested on the &lt;a href="http://rubyforge.org/tracker/index.php?func=detail&amp;amp;aid=14839&amp;amp;group_id=1513&amp;amp;atid=5924"&gt;rubyforge feature request&lt;/a&gt;, not only in that it checks the existence of the pid file, but it references options[:Chdir] instead of Dir.pwd in order to be compatible with the -c and --chdir ar_sendmail option.&amp;nbsp;  &lt;/p&gt;&lt;p&gt;&lt;strong&gt;3) Modify the do_exit method in ar_sendmail.rb to remove the pid file&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;  def do_exit&lt;br /&gt;    log &amp;quot;caught signal, shutting down and removing pid file&amp;quot;&lt;br /&gt;    self.remove_pid_file&lt;br /&gt;    exit&lt;br /&gt;  end &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;4) Create the monit file /etc/monit.d/ar_sendmail.teamsport.monitrc&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;check process ar_sendmail_teamsport&lt;br /&gt;  with pidfile /data/teamsport/current/log/ar_mailer.pid&lt;br /&gt;  start program = &amp;quot;/usr/bin/ar_sendmail -d -e production -c /data/teamsport/current/&amp;quot; as uid teamsport and gid teamsport&lt;br /&gt;  stop program = &amp;quot;/usr/local/bin/stop_ar_sendmail&amp;quot; as uid teamsport and gid teamsport&lt;br /&gt;  if totalmem is greater than 65.0 MB for 2 cycles then restart      # eating up memory?&lt;br /&gt;  if loadavg(5min) greater than 10 for 8 cycles then restart          # bad, bad, bad&lt;br /&gt;  if 20 restarts within 20 cycles then timeout                        # something is wrong, call the sys-admin&lt;br /&gt;  group ar_sendmail &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Note that I am using a simple shell script script called stop_ar_sendmail to stop the ar_sendmail process.&amp;nbsp; ar_sendmail has signal handlers for SIGINT and SIGTERM so we should use these signals to kill it, which will cause the do_exit method to be triggered. The stop_ar_sendmail script looks like this:&lt;/p&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;kill -2 `cat /data/teamsport/current/log/ar_mailer.pid` &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Originally I tried putting the contents of this shell script in the .montrc file like this:&lt;/p&gt;&lt;pre&gt;stop program = &amp;quot;/bin/kill -2 `cat /data/teamsport/current/log/ar_mailer.pid`&amp;quot; as uid teamsport and gid teamsport&amp;nbsp;&lt;/pre&gt;&lt;p&gt;This however does not work, since apparently monit doesn&amp;#39;t know what to do with the backticks. Alternatively you could use some sort of grep and kill script, such as pkill, to stop the ar_sendmail process. Ideally in the future, ar_sendmail will support some sort of stop command in the same manner as mongrel so that you could run &amp;quot;ar_sendmail stop&amp;quot; to stop it.&lt;/p&gt;&lt;p&gt;Once you have this all setup you can control ar_sendmail via monit. When creating the ar_sendmail.teamsport.monitrc file, make sure you change &amp;quot;teamsport&amp;quot; to the user that you want to run the process as.&amp;nbsp; Then do a &amp;quot;&lt;font color="#ff0000"&gt;sudo monit reload&lt;/font&gt;&amp;quot; and monit should see that ar_sendmail is not running and will start it for you. To make sure everything is working correctly try &amp;quot;&lt;font color="#ff0000"&gt;sudo monit stop ar_sendmail_teamsport&lt;/font&gt;&amp;quot; and &amp;quot;&lt;font color="#ff0000"&gt;sudo monit start ar_sendmail_teamsport&lt;/font&gt;&amp;quot; (replacing &amp;quot;teamsport&amp;quot; with the appropriate user name). &lt;/p&gt;&lt;p&gt;Other than not working well with monit out of the box, the only other issue I have with ar_sendmail is the memory footprint, which is dependent to some degree on your rails app. The ar_sendmail process for my app runs at around 50 MB, and just to send mail! I assume this is due to the fact that ar_sendmail loads the rails app&amp;#39;s environment.rb file. The environment.rb file runs the boot.rb file, which bootstraps and initializes the entire rails app. Additionally, our environment.rb has several other plugins required inside of it. I think the environment.rb file is loaded primarily just to get at the ActiveMailer smtp_settings, which is a slick way to allow for easy integration of ar_mailer with minimal changes to your existing rails app. Many people wouldn&amp;#39;t think twice about 50 MB, but rails hosts charge quite a bit for RAM. I can definitely envision a slimmed down ar_sendmail that doesn&amp;#39;t load the rails app&amp;#39;s environment.rb file, but it seems almost impossible to do this without making integration with existing rails apps more difficult.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>Wed, 05 Dec 2007 19:35:00 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:672193d6-be4f-4545-acdd-42e3f4f669d6</guid>
      <author>Luke Ludwig</author>
      <link>http://www.lukeludwig.com/blog/articles/2007/12/05/running-ar_sendmail-with-monit</link>
      <category>rails</category>
      <category>ar_mailer</category>
      <category>ar_sendmail</category>
      <category>monit</category>
      <trackback:ping>http://www.lukeludwig.com/blog/articles/trackback/6</trackback:ping>
    </item>
    <item>
      <title>"Running ar_sendmail with monit" by Gustav Paul</title>
      <description>thanks for this</description>
      <pubDate>Mon, 09 Jun 2008 13:52:27 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:fe904333-8465-4ae4-9b61-0767f5070374</guid>
      <link>http://www.lukeludwig.com/blog/articles/2007/12/05/running-ar_sendmail-with-monit#comment-848</link>
    </item>
    <item>
      <title>"Running ar_sendmail with monit" by Fernando</title>
      <description>sorry, i meant ActionMailer::ARSendmail.remove_pid_file</description>
      <pubDate>Fri, 18 Apr 2008 08:04:11 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:3df599bc-a7b5-4c8d-a138-a9b976f29bdf</guid>
      <link>http://www.lukeludwig.com/blog/articles/2007/12/05/running-ar_sendmail-with-monit#comment-565</link>
    </item>
    <item>
      <title>"Running ar_sendmail with monit" by Fernando</title>
      <description>thank's a lot, it's been a great help for me :)
Just one thing, i had to change the self.remove_pid_file calls to ActionMailer::ARSendmail.send_mail  in order to make it work</description>
      <pubDate>Fri, 18 Apr 2008 08:03:37 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:a65362d5-a8aa-4314-9b29-f91688c3f9db</guid>
      <link>http://www.lukeludwig.com/blog/articles/2007/12/05/running-ar_sendmail-with-monit#comment-564</link>
    </item>
    <item>
      <title>"Running ar_sendmail with monit" by Jatinder</title>
      <description>Jarkko, ActiveRecord can be used outside scope of a Rails app. 

Thanks for the wonderful write up, Luke!</description>
      <pubDate>Thu, 10 Apr 2008 22:58:55 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:b5da64df-d448-4c12-9a91-3c102fcbb50e</guid>
      <link>http://www.lukeludwig.com/blog/articles/2007/12/05/running-ar_sendmail-with-monit#comment-517</link>
    </item>
    <item>
      <title>"Running ar_sendmail with monit" by Jarkko Laine</title>
      <description>Thanks for an excellent tutorial! Another reason why ar_sendmail loads the environment is that it uses ActiveRecord to interface with the emails table in the database.</description>
      <pubDate>Tue, 18 Mar 2008 04:23:48 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:e37eab38-28d6-4173-830f-71deacf08460</guid>
      <link>http://www.lukeludwig.com/blog/articles/2007/12/05/running-ar_sendmail-with-monit#comment-282</link>
    </item>
  </channel>
</rss>
