Brandon Rice

Software development with a focus on web technologies.

Using Gdb to Debug Ruby

| Comments

At work, we were encoutering a few situations where Resque workers would hang indefinitely after forking. My first thought was to force the process to raise an exception in order to generate a stack trace which I would then be able to examine in the logs. However, sending TERM, INT, and QUIT signals to the process didn’t seem to have any affect. The process still hung, and I had nothing useful to look at in the logs. The only way to end the process was to send it a kill -9, which unfortunately means no stack trace and no clue as to what actually went wrong.

After this happened a few times, I realized that I needed to examine the running process for more information. My limited C/C++ exposure told me that gdb would be a great tool for this, but I wasn’t sure how I could get useful Ruby information after attaching to the running process. A little googling led me to an excellent blog post by Thoughtbot that included some helpful gdbinit definitions:

~/.gdbinit
1
2
3
4
5
6
7
define redirect_stdout
  call rb_eval_string("$_old_stdout, $stdout = $stdout, File.open('/tmp/ruby-debug.' + Process.pid.to_s, 'a'); $stdout.sync = true")
end

define ruby_eval
  call(rb_p(rb_eval_string_protect($arg0,(int*)0)))
end

The first function redirects the process standard out to a temporary file which you can then tail -f in order to see what’s going on. The second function allows you execute arbitrary Ruby code inside the process. Assuming you have the above definitions in your ~/.gdbinit file, and a running irb process with pid 12345, the process would look like:

1
2
3
4
$ gdb /home/brandon/.rvm/rubies/ruby-2.1.0/bin/ruby 12345
(gdb) redirect_stdout
$1 = 20
(gdb) ruby_eval("puts caller.join('\n')")

Obviously, substitute your own path to the appropriate Ruby binary. In a separate window, you can tail -f /tmp/ruby-debug.12345 after the first command. The second command will then output the current execution stack for the running process. Your ruby_eval calls are running in the context of the currently executing code. So, for instance, you could see a list of currently defined local variables with Kernel#local_variables. You could then examine each of those variables in turn in order to get an idea of what was going on at that particular point in your code.

If you’re curious as I was about the call to rb_eval_string_protect() (which is an internal C function in the Ruby source), the first argument is the string of Ruby code that’s being executed. The second argument is an integer pointer to a defined error constant. In this case, 0 means the code executes successfully. A non-0 number would indicate an error, and the function would return nil.

These little gdb tricks have changed my world when it comes to debugging. I use this technique all the time.

If you enjoyed this post, please consider subscribing.

Ruby Class Method Mixins

| Comments

Adding custom class methods is a common Ruby-ism that’s used in many gems. Maybe you’ve used state_machine to do something like this:

1
2
3
4
5
class MyMachine
  state_machine :state do
    # other stuff
  end
end

Fairly straight-forward. Plenty of libraries use class methods like this. You can easily group related methods together in your own modules, and then have them defined on the class when the module is later included. This is accomplished with the Module#included method like so:

1
2
3
4
5
6
7
8
9
10
11
module MyModule
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def class_do_something(arg)
      # stuff
    end
  end
end

Then, include this module in one of your other classes:

1
2
3
4
5
class MyClass
  include MyModule

  class_do_something :foo
end

A friend of mine has been working on a Ruby MUD server that I’ve been helping with when time permits. One thing we want to do is persist game objects to disk using any number of backends (Mongo, SQLite, etc.). We want an API that’s storage-type agnostic which can talk to the appropriate mechanism by way of an adapter. The adapter should be hidden from the main application. We want to be able to write object classes that might look like this:

1
2
3
4
5
6
class Weapon
  include Persistable

  field :damage, :float
  field :weight, :int
end

This is very similar to the Mongoid syntax (a gem my friend and I are both fans of). Using the above pattern in our Persistable module allows us to accomplish exactly what we’re going for. The full code after our initial refactor is below.

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
module Persistable
  attr_reader :_id

  def _id
    _id ||= SecureRandom.uuid
  end

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def self.extended(base)
      base.instance_eval do
        class << self; attr_reader :fields; end
        @fields = []
      end
    end

    def field(name)
      attr_accessor name
      @fields << name
    end

    def read_only_field(name)
      attr_reader name
      @fields << name
    end
  end

end

If you enjoyed this post, please consider subscribing.

Rails Validator Classes and Instance Vars

| Comments

Have you ever used a custom validator class in Rails? I’m referring to a subclass of ActiveModel::Validator which you then include inside your model such as…

1
2
3
4
5
6
7
class MyModel < ActiveRecord::Base

  include ActiveModel::Validations
  validates_with MyValidator

  # ...etc.
end

This allows you to define your validation methods in a custom class. It can be useful for extracting validation behavior out of your model. However, what you might not know is how this class is instantiated by Rails. I assumed that a new instance of my validator would be created each time validation was performed on an instance of the model during a web request. I also assumed that the validator instance would stick around if multiple validation attempts were made. Based on this assumption, I attempted to memoize the model instance inside my validator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MyValidator < ActiveModel::Validator
  attr_reader :model

  def validate(record)
    @model ||= record
    a_validation_method
    another_validation_method
  end

  private

  def a_validation_method
    if !check_for_validity
      model.errors[:base] << 'No good'
    end
  end

  def another_validation_method
    # etc...
  end
end

This won’t work, and leads to some unexpected behavior. Everything seemed fine while submitting my form via the browser, but my tests were failing. Things that should have been valid weren’t, and vice versa. This eventually led me to do a little research on how Rails uses validators.

ActiveModel::Validations::ClassMethods#validates_with
1
2
3
4
5
6
7
8
9
10
11
def validates_with(*args, &block)
  options = args.extract_options!
  args.each do |klass|
    validator = klass.new(options, &block)
    validator.setup(self) if validator.respond_to?(:setup)

    # more stuff...

    validate(validator, options)
  end
end

The moral of the story is that validates_with is a class method that creates a single instance of the validator when the model class is first loaded. If you memoize an instance variable inside the validator, it will not be replaced on successive calls to the validate method. In other words, the validator might be trying to validate the wrong object.

If you enjoyed this post, please consider subscribing.