Tag Archive > workling

Checkout Hoptoad by thoughtbot, inc.

Dave » 15 June 2009 » In Technology, rails » 2 Comments

I’ve been using Hoptoad for about two months now, and I’m sold. Hoptoad is a product by thoughbot, inc. Previously, I’ve always used the excellent exception_notification plugin. The exception_notification plugin is easy to use, and it works great. However, there are a couple of problems with it.

  1. You could flood your inbox if there is a bad problem on a popular page.
  2. It’s difficult to collect all the emails and track errors.

Enter Hoptoad. Hoptoad solves both problems, and it is super simple to use and setup. It’s free for one project and two users. If that isn’t enough for you, the premium services are very reasonable.

How does it solve both problems? First, Hoptoad will still send you an email when there is an error. However, it won’t flood your inbox if there are hundreds of the same email. Second, Hoptoad provides a simple web-based system that groups your errors by exception class. That makes it easier to track down problems. Finally, you can mark errors resolved so you don’t have to wade through noise to solve the real problems.

Hoptoad installation:

REMOVE EXCEPTION_NOTIFIER

  1. In your ApplicationController, REMOVE this line:include ExceptionNotifiable
  2. In your config/environment* files, remove all references to ExceptionNotifier.
  3. Remove the vendor/plugins/exception_notifier directory.

INSTALL HOPTOAD_NOTIFIER

From your project’s RAILS_ROOT, run:

script/plugin install git://github.com/thoughtbot/hoptoad_notifier.git

CONFIGURATION

You should have something like this in config/initializers/hoptoad.rb.

HoptoadNotifier.configure do |config|
  config.api_key = '1234567890abcdef'  # You get your key when you sign up
end

(Please note that this configuration should be in a global configuration, and is not enrivonment-specific. Hoptoad is smart enough to know what errors are caused by what environments, so your staging errors don’t get mixed in with your production errors.)

Once you do the above, any Exception not caught by your controllers will be sent to Hoptoad where where they can be aggregated, filtered, sorted, analyzed, massaged, and searched.

Now, if you have read anything I’ve done before, you know I do a lot of asynchronous processing with Workling. By default, Hoptoad will not log errors from anything outside of your controllers. Fear not. Hoptoad provides a webservice API to send errors. Here is an example.

In workling/lib/workling/base.rb:

    # takes care of suppressing remote errors but raising Workling::WorklingNotFoundError
    # where appropriate. swallow workling exceptions so that everything behaves like remote code.
    # otherwise StarlingRunner and SpawnRunner would behave too differently to NotRemoteRunner.
    def dispatch_to_worker_method(method, options)
      begin
        self.send(method, options)
      rescue Exception => e
        raise e if e.kind_of? Workling::WorklingError
        logger.error "Workling Error: runner could not invoke #{ self.class }:#{ method } with #{ options.inspect }. error was: #{ e.inspect }\n #{ e.backtrace.join("\n") }"
        # DND: Let HopToad know of the issue
        params = options || {}
        HoptoadNotifier.notify(
          :error_class => "Workling Error - #{e.class.name}",
          :error_message => "Workling Error(#{e.class.name}): #{e.message}",
          :request => { :params => params.merge(:worker_class => self.class.name, :worker_method => method) })
        # DND: end of change
      end
    end

Now, any error not caught by your workers will be sent to Hoptoad for processing. You can use a similar method from Rake tasks or any scripts that run outside of controllers. Remember, Hoptoad will collect errors by :error_class, so you can use different classes to separate errors into bins based on where they came from.

Give Hoptoad a try. You will not be disappointed.

Continue reading...

Tags: , , ,

Workling Timing Issue

Dave » 28 May 2009 » In Technology » No Comments

As you probably noticed already, I use Workling a lot, and I wrote about it a few times (Part 1, Part 2, Part 3). One minor gotcha to be aware of is that you need to make sure you handle it when Workling is too fast. A common use of Workling is to make a call in an after_save method. For example:

class User < ActiveRecord::Base
  def after_save
    MyWorker.asynch_geocode_address(:user_id => self.id)
  end
end
class MyWorker < Workling::Base
  def geocode_address(options = {})
    user = User.find(options[:user_id])
    user.geocode_address
  end
end

Pretty straight forward, right? Unfortunately, what you will find is that often your worker will get called so fast on create that ActiveRecord hasn’t committed the transaction yet, and User.find will fail. To get around this, you need to write your workers that could be called from after_save/after_create to handle this condition. Instead of the above, you need to do the following:

class MyWorker < Workling::Base
  def geocode_address(options = {})
    retries = 3
    begin
      user = User.find(options[:user_id])
      user.geocode_address
    rescue => err
      if (retries -= 1) > 0
        sleep(0.2)  # Give ActiveRecord a chance to save
        retry
      end
      raise err
    end
  end
end

Now we catch the exception that ActiveRecord throws when it can’t find the new user yet. Waiting a short time and trying a few times gives ActiveRecord a chance to commit the record.

Enjoy asynchronous processing…

Continue reading...

Tags:

Replacing Mongrel with Passenger (mod_rails)

Dave » 23 March 2009 » In Technology » 6 Comments

I’ve been using Apache + Mongrel for a while now. I read about Passenger when it first came out, but I never felt the need to bother with it since I have a bunch of recipes for Apache and Mongrel (see a previous posts about background tasks with Workling). The other day, I figured I would give it a shot. Now, I think I found my new way to deploy Rails apps. It is so simple, and it works well.

Some people write off Passenger because it uses Apache and not Nginx. Nginx is a little faster, and it is the latest “best practice,” but I haven’t had issues with Apache in forever. As for the speed issues, I don’t see it being a big factor to the end users. A few milliseconds is not going to be noticeable, at least for my apps.

Installation could not be simpler.

  1. sudo gem install passenger
  2. sudo passenger-install-apache2-module
  3. Follow the instructions the previous script displays
  4. Restart Apache
  5. Done!

If your development machine is OSX, don’t bother to manually change the Apache conf for your application and your hosts file just yet. You can use the Passenger Preference Pane instead. This little beauty will make all the changes to your Apache config files for you. One of the benefits is that you can have dozens of small Rails projects configured, and all are available with their own url — no need to run script/server for each. For install, the site explains it pretty well, so I won’t go into it here.

I did run into one problem on my Leopard machine. My default Apache config file had the httpd process running as the _www user, but my project files are owned by me. The result is that I kept getting permission errors accessing files in my project. I’m sure there is a solution to the problem by changing the permissions on my project files, but I didn’t find it. I ended up running httpd as me, and that fixed it. I did not have this issue on my test or production systems.

Even with the problem, the entire process took me less than an hour. What I gained is the following:

  • I no longer have to run script/server every time I switch to a new application for development.
  • All of my apps on my dev machine have their own url (myapp.local, etc.) instead of localhost:3000.
  • My god.rb config no longer has to watch Mongrel processes. It’s all in Apache.
  • No Mongrel cluster or load balancing in Apache configs among multiple Mongrels. Apache just operates normally, and my config files are a lot simpler.
  • Mongrel hasn’t had any updates in while, but Passenger is still under active development.
  • An added benefit is that my test/staging server performs better since only the applications being used are running. By default Passenger will drop any process not accessed in 300 seconds (you can change that).

All of the required changes involved removing any references to Mongrel in my god.rb config, apache config, and my deploy.rb. The only thing I needed to actually change is how to start/stop/restart my application. Remember, there is no mongrel process to start or stop. It’s all Apache. Passenger makes it easy, however. All you need to do is touch tmp/restart.txt. If that file is modified, then Passenger will restart your application.

My updated config/deploy.rb:

namespace :deploy do

  desc "Start the application"
  task :start, :roles => :app do
    run "touch #{current_release}/tmp/restart.txt"
    sudo "god start listeners"
  end

  desc "Stop the application"
  task :stop, :roles => :app do
    # Do nothing for application
    sudo "god stop listeners"
  end

  desc "Restart Application"
  task :restart, :roles => :app do
    run "touch #{current_release}/tmp/restart.txt"
    sudo "god restart listeners"
  end
end

Give Passenger a try. I think you will like it.

Continue reading...

Tags: , , ,